问题
Command framed to identify if Xcode is running on Mac: cmd = "ps -ax | grep -v grep | grep Xcode"
If Xcode is not running, then above command works well with Popen
method of subprocess
module, but raises a CalledProcessError
with check_output
method. I tried to inspect the stderr
through the following code, but failed to get appropriate information to understand the reason.
from subprocess import check_output, STDOUT, CalledProcessError
psCmd = "ps -ax | grep -v grep | grep Xcode"
o = None
try:
o = check_output(psCmd, stderr=STDOUT, shell=True)
except CalledProcessError as ex:
print 'Error:', ex, o
Exception message is as follows:
Error: Command 'ps -ax | grep -v grep | grep Xcode' returned non-zero exit status 1 None
Question: Why the above command works with Popen, but fails with check_output ?
Note: Command works well with both approach, if Xcode is running.
回答1:
check_output()
works as expected. Here's its simplified implementation in terms of Popen()
:
def check_output(cmd):
process = Popen(cmd, stdout=PIPE)
output = process.communicate()[0]
if process.returncode != 0:
raise CalledProcessError(process.returncode, cmd, output=output)
return output
grep
returns 1
if it hasn't found anything i.e., you should expect the exception if Xcode is not running.
Note: as the implementation shows, you can get the output even if the exception occurs:
#!/usr/bin/env python
from subprocess import check_output, STDOUT, CalledProcessError
cmd = "ps -ax | grep -v grep | grep Xcode"
try:
o = check_output(cmd, stderr=STDOUT, shell=True)
returncode = 0
except CalledProcessError as ex:
o = ex.output
returncode = ex.returncode
if returncode != 1: # some other error happened
raise
You could probably use pgrep -a Xcode
command instead (note: starts with p
) or use psutil
module for a portable code:
#!/usr/bin/env python
import psutil # $ pip install psutil
print([p.as_dict() for p in psutil.process_iter() if 'Xcode' in p.name()])
回答2:
From the Python docs: "If the return code was non-zero it raises a CalledProcessError.". That's what happens to you when Xcode isn't running; the final grep Xcode
exits with a non-zero status because grep
couldn't find the string Xcode
that you're looking for. Hence, check_output()
will raise the exception.
BTW, I found this on the Python subprocess documentation.
回答3:
If your grep command grep Xcode
returns no result then the returncode
of the command will be non-zero, that's why check_output
is calling CalledProcessError
, which is what you are seeing in the output of print
command
To get the output of your command be it error or success use following piece of code:-
#!/usr/bin/python
from subprocess import check_output, STDOUT, CalledProcessError
psCmd = "ps -aef | grep -v grep | grep Xcode"
o = None
o = check_output(psCmd+";exit 0", stderr=STDOUT, shell=True)
check_output will only show you the output of the command if it's return code is 0
else it calls an exception.
回答4:
The purpose of check_output
is to make sure that the command you ran completed successfully. It's supposed to fail if grep Xcode
does not return success.
What you want would be a lot simpler with the searching in Python, anyway.
output = check_output(['ps', '-ax'], shell=False)
if 'Xcode' in output:
print('Xcode appears to be running')
This has the additional (very minor) benefit over the shell version that it actually fails if ps
fails for some reason. The shell would simply ignore the exit code of ps
when it's not at the end of a pipeline.
来源:https://stackoverflow.com/questions/28675138/python-check-output-fails-with-exit-status-1-but-popen-works-for-same-command