How to determine subprocess.Popen() failed when shell=True - python

Windows version of Python 2.6.4: Is there any way to determine if subprocess.Popen() fails when using shell=True?
Popen() successfully fails when shell=False
>>> import subprocess
>>> p = subprocess.Popen( 'Nonsense.application', shell=False )
Traceback (most recent call last):
File ">>> pyshell#258", line 1, in <module>
p = subprocess.Popen( 'Nonsense.application' )
File "C:\Python26\lib\subprocess.py", line 621, in __init__
errread, errwrite)
File "C:\Python26\lib\subprocess.py", line 830, in
_execute_child
startupinfo)
WindowsError: [Error 2] The system cannot find the file specified
But when shell=True, there appears to be no way to determine if a Popen() call was successful or not.
>>> p = subprocess.Popen( 'Nonsense.application', shell=True )
>>> p
>>> subprocess.Popen object at 0x0275FF90>>>
>>> p.pid
6620
>>> p.returncode
>>>
Ideas appreciated.
Regards,
Malcolm

returncode will work, although it will be None until you've called p.poll(). poll() itself will return the error code, so you can just do
if a.poll() != 0:
print ":("

In the first case it fails to start, in the second - it successfully starts shell which, in turn, fails to execute the application. So your process has been properly spawned, exited and waits for you to inquire about its exit code. So, the thing is, unless your shell or environment (e.g. no memory) is utterly broken there's no way Popen itself may fail.
So, you can safely .poll() and .wait() on it to get all the sad news.

Related

subprocess.check_output(): OSError file not found in Python

Executing following command and its variations always results in an error, which I just cannot figure out:
command = "/bin/dd if=/dev/sda8 count=100 skip=$(expr 19868431049 / 512)"
print subprocess.check_output([command])
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python2.7/subprocess.py", line 566, in check_output
process = Popen(stdout=PIPE, *popenargs, **kwargs)
File "/usr/lib/python2.7/subprocess.py", line 710, in __init__
errread, errwrite)
File "/usr/lib/python2.7/subprocess.py", line 1327, in _execute_child
raise child_exception
OSError: [Errno 2] No such file or directory
WHich file it is referring to ? other commands like ls,wc are running correctly though, the command is also running well on terminal but not python script.
Your command is a list with one element. Imagine if you tried to run this at the shell:
/bin/'dd if='/dev/'sda8 count=100 skip=$(expr 19868431049 '/' 512)'
That's effectively what you're doing. There's almost certainly no directory named dd if= in your bin directory, and there's even more almost certainly no dev directory under that with an sd8 count=100 skip=$(expr 19868431049 directory with a program named 512 in it.
What you want is a list where each argument is its own element:
command = ['/bin/dd', 'if=/dev/sda8', 'count=100', 'skip=$(expr 19868431049 / 512)']
print subprocess.check_output(command) # notice no []
But that brings us to your second problem: $(expr 19868431049 / 512) isn't going to be parsed by Python or by dd; that's bash syntax. You can, of course, just do the same thing in Python instead of in bash:
command = ['/bin/dd', 'if=/dev/sda8', 'count=100',
'skip={}'.format(19868431049 // 512)]
print subprocess.check_output(command)
Or, if you really want to use bash for no good reason, pass a string, rather than a list, and use shell=True:
command = "/bin/dd if=/dev/sda8 count=100 skip=$(expr 19868431049 / 512)"
print subprocess.check_output(command, shell=True) # still no []
Although that still isn't going to work portably, because the default shell is /bin/sh, which may not know how to handle bashisms like $(…) (and expr, although I think POSIX requires that expr exist as a separate process…). So:
command = "/bin/dd if=/dev/sda8 count=100 skip=$(expr 19868431049 / 512)"
print subprocess.check_output(command, shell=True, executable='/bin/bash')
This worked for me using subprocess.popen
command = "echo $JAVA_HOME"
proc = subprocess.Popen(command,stdout=subprocess.PIPE,shell=True)

data stream python subprocess.check_output exe from another location

I would like to run an exe from this directory:/home/pi/pi_sensors-master/bin/Release/
This exe is then run by tying mono i2c.exe and it runs fine.
I would like to get this output in python which is in a completely different directory.
I know that I should use subprocess.check_output to take the output as a string.
I tried to implement this in python:
import subprocess
import os
cmd = "/home/pi/pi_sensors-master/bin/Release/"
os.chdir(cmd)
process=subprocess.check_output(['mono i2c.exe'])
print process
However, I received this error:
The output would usually be a data stream with a new number each time, is it possible to capture this output and store it as a constantly changing variable?
Any help would be greatly appreciated.
Your command syntax is incorrect, which is actually generating the exception. You want to call mono i2c.exe, so your command list should look like:
subprocess.check_output(['mono', 'i2c.exe']) # Notice the comma separation.
Try the following:
import subprocess
import os
executable = "/home/pi/pi_sensors-master/bin/Release/i2c.exe"
print subprocess.check_output(['mono', executable])
The sudo is not a problem as long as you give the full path to the file and you are sure that running the mono command as sudo works.
I can generate the same error by doing a ls -l:
>>> subprocess.check_output(['ls -l'])
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python2.7/subprocess.py", line 537, in check_output
process = Popen(stdout=PIPE, *popenargs, **kwargs)
File "/usr/lib/python2.7/subprocess.py", line 679, in __init__
errread, errwrite)
File "/usr/lib/python2.7/subprocess.py", line 1249, in _execute_child
raise child_exception
OSError: [Errno 2] No such file or directory
However when you separate the command from the options:
>>> subprocess.check_output(['ls', '-l'])
# outputs my entire folder contents which are quite large.
I strongly advice you to use the subprocess.Popen -object to deal with external processes. Use Popen.communicate() to get the data from both stdout and stderr. This way you should not run into blocking problems.
import os
import subprocess
executable = "/home/pi/pi_sensors-master/bin/Release/i2c.exe"
proc = subprocess.Popen(['mono', executable])
try:
outs, errs = proc.communicate(timeout=15) # Times out after 15 seconds.
except TimeoutExpired:
proc.kill()
outs, errs = proc.communicate()
Or you can call the communicate in a loop if you want a 'data-stream' of sort, an answer from this question:
from subprocess import Popen, PIPE
executable = "/home/pi/pi_sensors-master/bin/Release/i2c.exe"
p = Popen(["mono", executable], stdout=PIPE, bufsize=1)
for line in iter(p.stdout.readline, b''):
print line,
p.communicate() # close p.stdout, wait for the subprocess to exit

Popen error: "[Errno 2] No such file or directory" when calling shell function

I have some custom commands.
This works:
subprocess.Popen(['python'], stdout=subprocess.PIPE)
But if I have my own system commands like deactivate, I get that error
Traceback (most recent call last):
File "runner2.py", line 21, in <module>
main()
File "runner2.py", line 18, in main
subprocess.Popen(['deactivate',], stdout=subprocess.PIPE)
File "/usr/lib/python2.6/subprocess.py", line 633, in __init__
errread, errwrite)
File "/usr/lib/python2.6/subprocess.py", line 1139, in _execute_child
raise child_exception
OSError: [Errno 2] No such file or directory
Let alone I need to execute this under my sandbox virtualenv.
Try add an extra parameter shell=True to the Popen call.
Just a note. shell=True was likely the correct solution to the o.p., since they did not make the following mistake, but you can also get the "No such file or directory" error if you do not split up your executable from its arguments.
import subprocess as sp, shlex
sp.Popen(['echo 1']) # FAILS with "No such file or directory"
sp.Popen(['echo', '1']) # SUCCEEDS
sp.Popen(['echo 1'], shell=True) # SUCCEEDS, but extra overhead
sp.Popen(shlex.split('echo 1')) # SUCCEEDS, equivalent to #2
Without shell=True, Popen expects the executable to be the first element of args, which is why it fails, there is no "echo 1" executable. Adding shell=True invokes your system shell and passes the first element of args to the shell. i.e. for linux, Popen(['echo 1'], shell=True) is equivalent to Popen('/bin/sh', '-c', 'echo 1') which is more overhead than you may need. See Popen() documentation for cases when shell=True is actually useful.
You have to give the full path to your program deactivate and then it the subprocess module should be able to find it.
I'm spawning subprocesses like that:
SHUTDOWN_CMD = os.path.sep.join(["c:", "windows", "system32", "shutdown.exe"])
def abortShutdown():
os.spawnv(os.P_NOWAIT, SHUTDOWN_CMD,
[SHUTDOWN_CMD, '/A'])
time.sleep(3)
I'm not using subprocess since Python 2.5 does not support it. I had to use use the FULL path to have it working and I guess you also have to use the full path to your custom commands.

subprocess piping output on Windows

I've got this piece of code that works fine on Linux but fails on Windows. Process is created fine, but I get an error and nothing is read from pipe:
p = subprocess.Popen(['python', '-u', self.file_to_run,
'-s', '-g', '-i', self.input_file],
universal_newlines=True,
stdout=subprocess.PIPE)
...
out = p.stdout.readline().rstrip()
Error I get is
Traceback (most recent call last):
File "bench.py", line 59, in <module>
multi.add_process()
File "bench.py", line 47, in add_process
stdout=subprocess.PIPE)
File "c:\python\v2.5.1-ast3\...\lib\subprocess.py", line 615, in __init__
self.stdout = os.fdopen(c2pread, 'rU', bufsize)
OSError: [Errno 22] Invalid argument
I actually create multiple such processes and based on their output calculate some values, but that is irrelevant. What I need to do is, run the script with certain arguments multiple times and parse the data piped from stdout of each process.
try using sys.executable instead of 'python' in your subprocess args. I think this is because Python is not in the PATH on Windows.
Also check the value of self.file_to_run and self.input_file which must be strings and not None or strange stuff, but this probably won't cause an OSError.

Python - Subprocess - How to call a Piped command in Windows?

How do I run this command with subprocess?
I tried:
proc = subprocess.Popen(
'''ECHO bosco|"C:\Program Files\GNU\GnuPG\gpg.exe" --batch --passphrase-fd 0 --output "c:\docume~1\usi\locals~1\temp\tmptlbxka.txt" --decrypt "test.txt.gpg"''',
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
)
stdout_value, stderr_value = proc.communicate()
but got:
Traceback (most recent call last):
...
File "C:\Python24\lib\subprocess.py", line 542, in __init__
errread, errwrite)
File "C:\Python24\lib\subprocess.py", line 706, in _execute_child
startupinfo)
WindowsError: [Errno 2] The system cannot find the file specified
Things I've noticed:
Running the command on the windows
console works fine.
If I remove the
ECHO bosco| part, it runs fine the
the popen call above. So I think
this problem is related to echo or
|.
First and foremost, you don't actually need a pipe; you are just sending input. You can use subprocess.communicate for that.
Secondly, don't specify the command as a string; that's messy as soon as filenames with spaces are involved.
Thirdly, if you really wanted to execute a piped command, just call the shell. On Windows, I believe it's cmd /c program name arguments | further stuff.
Finally, single back slashes can be dangerous: "\p" is '\\p', but '\n' is a new line. Use os.path.join() or os.sep or, if specified outside python, just a forward slash.
proc = subprocess.Popen(
['C:/Program Files/GNU/GnuPG/gpg.exe',
'--batch', '--passphrase-fd', '0',
'--output ', 'c:/docume~1/usi/locals~1/temp/tmptlbxka.txt',
'--decrypt', 'test.txt.gpg',],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
)
stdout_value, stderr_value = proc.communicate('bosco')
You were right, the ECHO is the problem. Without the shell=True option the ECHO command cannot be found.
This fails with the error you saw:
subprocess.call(["ECHO", "Ni"])
This passes: prints Ni and a 0
subprocess.call(["ECHO", "Ni"], shell=True)

Categories

Resources