Why Does Python Call a Subprocess Command Incorrectly? - python

This is a follow up on a previous question as I have made progress(which is irrelevant at this point). It is worth noting that I am learning python and barely know what I am doing, however, I am familiar with programming. I am trying to call an SCP command in the windows terminal through python. However, it is not doing the desired effect. The script runs smoothly with no errors and it prints the debug commands as I have written them. However, the SCP call does not actually go through on the other end. To make sure I have the right command, I have it set to print the same command that it called afterwards. When I copy this printed command and paste it into the windows command terminal, it gives the desired effect. Why is the same command not working correctly in python? Thanks. This is my script:
import subprocess
subprocess.run(['scp', 'c:/users/<name>/desktop/OOGA.txt', 'pi#<IP>:here/'], shell=True)
print ("done")
print ('scp', 'c:/users/<name>/desktop/OOGA.txt', 'pi#<IP>:here/')

Try using raw string if shell is set to True:
from subprocess import run as subrun
status = subrun(r'scp c:/users/<name>/desktop/OOGA.txt pi#<IP>:here/',shell=True)
print("Done")
print(status)

Related

Running batch file with subprocess.call does not work and freezes IPython console

This is a frequent question, but reading the other threads did not solve the problem for me.
I provide the full paths to make sure I have not made any path formulation errors.
import subprocess
# create batch script
myBat = open(r'.\Test.bat','w+') # create file with writing access
myBat.write('''echo hello
pause''') # write commands to file
myBat.close()
Now I tried running it via three different ways, found them all here on SO. In each case, my IDE Spyder goes into busy mode and the console freezes. No terminal window pops up or anything, nothing happens.
subprocess.call([r'C:\\Users\\felix\\folders\\Batch_Script\\Test.bat'], shell=True)
subprocess.Popen([r'C:\\Users\\felix\\folders\\Batch_Script\Test.bat'], creationflags=subprocess.CREATE_NEW_CONSOLE)
p = subprocess.Popen("Test.bat", cwd=r"C:\\Users\\felix\\folders\\Batch_Script\\")
stdout, stderr = p.communicate()
Each were run with and without the shell=True setting, also with and without raw strings, single backslashes and so on. Can you spot why this wont work?
Spyder doesn't always handle standard streams correctly so it doesn't surprise me that you see no output when using subprocess.call because it normally runs in the same console. It also makes sense why it does work for you when executed in an external cmd prompt.
Here is what you should use if you want to keep using the spyder terminal, but call up a new window for your bat script
subprocess.call(["start", "test.bat"], shell=True)
start Starts a separate Command Prompt window to run a specified program or command. You need shell=True because it's a cmd built-in not a program itself. You can then just pass it your bat file as normal.
You should use with open()...
with open(r'.\Test.bat','w+') as myBat:
myBat.write('echo hello\npause') # write commands to file
I tested this line outside of ide (by running in cmd) and it will open a new cmd window
subprocess.Popen([r'Test.bat'], creationflags=subprocess.CREATE_NEW_CONSOLE)
Hey I have solution of your problem :)
don't use subprocess instead use os
Example :
import os
myBatchFile = f"{start /max} + yourFile.bat"
os.system(myBatchFile)
# "start /max" will run your batch file in new window in fullscreen mode
Thank me later if it helped :)

Calling a python script from another python script with arguments does not work

I am well aware that there are multiple threads dealing with this problem because I used them in an attempt to self-teach me how to do it. However, for me it does not work and I wondered if someone could help me find my error.
So I got one program (let's call it prog1) that calls a script for every string-variable like this:
os.system(r'C:\Users\user\docs\bla\script.py %s'%variable)
In script.py I now just wanted to test if this call worked by disabling all code but just doing:
def main(string):
print(string)
root
if __name__ == "__main__":
print('I got executed')
main(sys.argv[1])
The Problem is, if I execute prog1 nothing happens. No errer - so it runs through and the console pops up for a Brief second. However, nothing happens - no string is printed. If I execute script.py directly it works though.
EDIT: I got it to execute without error with the subprocess package by using:
subprocess.call(r'C:\...\script.py' %s' %variable,shell = True)
However, the problem stays the same - nothing happens. Or well, I noticed now that in the Background a Windows window pops up asking me with which program I want to execute files with the ending '.py' but this is not helping me, because I want to execute in console :(
Try using the subprocess module, it allows for more flexible parametres and other configuration changes :
import subprocess
subprocess.check_call(["python.exe", r"C:\Users\user\docs\bla\script.py", variable])
And when executed :
subprocess.check_call(["python", r"C:\Users\user\docs\bla\script.py", "Blue"])
I got executed
Blue
More information about the subprocess : https://docs.python.org/2/library/subprocess.html

Why doesn't the rest of the code after call() work? [duplicate]

I have a python script which when run, logs information on the terminal, i want to send this logging information to a text file,
To achieve this in the beginning of the file i am inserting
import subprocess
subprocess.call(['script', 'logfile'])
and at the end of the file,i put in,
subprocess.call(['exit'])
The problem with this is when it calls the first commandscript logfile,it terminates the script,
Any suggestions on how i could make this work would be really helpful,Thanks in advance
The problem is that subprocess.call isn't returning until the shell spawned by script exits, at which point your Python script will resume.
The simplest way to do what you want is to call script itself with your Python script as an argument. Instead of
#!/usr/bin/python
import subprocess
subprocess.call(['script', 'logfile'])
# Rest of your Python code
subprocess.call(['exit'])
you will use
#!/usr/bin/python
import os
import sys
if '_underscript' not in os.environ:
os.environ['_underscript'] = "yes"
cmd_args = ['script', 'logfile', 'python'] + sys.argv
os.execvp('script', cmd_args)
# Rest of your Python code
The environment variable prevents your script from entering an infinite loop of re-running itself with script. When you run your Python script, it first checks its environment for a variable that should not yet exist. If it doesn't, it sets that variable, then runs script to re-run the Python script. execvp replaces your script with the call to script; nothing else in the Python script executes. This second time your script runs, the variable _underscript does exist, meaning the if block is skipped and the rest of your script runs as intended.
Seems like that's the expected behaviour of subprocess.call(...). If you want to capture the output of the script to a file, you'll need to open a new file handler in write mode, and tell the subprocess.call where to direct the stdout, which is the terminal output you typically would see.
Try:
import subprocess
f = open('/tmp/mylogfile.log', 'w')
subprocess.call(['/path/to/script'], stdout=f)
f.close()
Then in the terminal you can run tail /tmp/mylogfile.log to confirm.
I'm not sure the last exit call is required for what you're trying to achieve.
You can read more in the python docs, depending which version of Python you're using. https://docs.python.org/2/library/subprocess.html
The file doesn't need to pre-exist. Hope that helps!

Python subprocess.run with stderr=subprocess.PIPE redirects input(text)

I wrote a program (myProg.py) that uses subprocess module to run other python programs through the run function. I noticed that arg in input(arg) statements in these other python programs are not being displayed to the console (stdout), while args in print(args) are displayed properly. This only happens when I run my program through console. This does not happen when I run my program through LiClipse.
Here is the simplest way to replicate this situation:
Using python 3.6.2, and windows 10
create a python program containing the following two lines and save it as someProgram.py:
a = input("Enter anything")
print("a has: " + a)
open cmd, type: python
type: import subprocess
type: subprocess.run(["python", "path..to..someProgram.py"], stderr=subprocess.PIPE)
No ouptut so far but the interpreter is waiting on input... type something and hit Enter.
You will see the output from the print statement.
If you remove , stderr=subprocess.PIPE you will see the correct outputs.
Now, save the code from steps 2 & 3 in another file, call it myProg.py in the same folder as someProgram.py. Run myProg.py from LiClipse. You will find that the myProg.py runs fine and produces the correct outputs.
My questions are:
Why is this problem with subprocess.run happening
How can I solve it
Why would there be a difference between running code through commandline and through an IDE.
input function print prompt text to stderr, this is a known issue
you redirected stderr, therefore prompt text not shown, when you run from LiClipse, stderr not get redirected.
you could output prompt by your self, like:
print("Enter anything", end='')
a = input()
alternatively, import readline module before input, then input will use GNU readline lib (if you have), which prints to stdout. While in your case, the program runs as a subprocess, you could still achieve this:
python -c "import readline; import runpy; runpy.run_path('/path/to/program.py')"

Python code acting differently than when run in terminal

When I pass my mpirun command through terminal, the normal (and expected) outcome is an output file with a bunch of data in it.
However when I pass the code through my python script, all of the output files that are expected are created, however they contain no data. Is there any global explanation for this? I have tried the code many different ways, using both os.system and subprocess. I have also tried running the code in the background as well as just running. And I have also tried just having the program spit out the data vs. saving it to the output file, and all give the same result.
Here is the code:
os.system("mpirun -np 4 /home/mike/bin/Linux-ifort_XE_openmpi-1.6_emt64/v2_0_1/Pcrystal > mgo.out")
The simplest way to get that behavior is if mpirun is not being successfully run.
For instance if, from the command line, I run
not_actually_a_command > myFile.txt
myFile.txt will be created, but will be empty (the "command not found" message is printed to stderr so won't be caught by ">").
Try using the fully resolved path to mpirun
There doesn't seem to be something inherently wrong with your approach. When I do
os.system("echo hello, world >hello.txt")
it ends up with "hello, world" in it, so if you get your command to run it should work for you.
You should start with providing a complete path
os.system("/complete/path/to/mpirun
and print the result, print(os.system...etc.),
and post the error so we know what is wrong.
When using the subprocess module it may require a "shell=True"

Categories