python check_output fails with exit status 1 but Popen works for same command

会有一股神秘感。 提交于 2019-12-30 03:34:54

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!