子进程检查输出返回码

78

我正在使用:

grepOut = subprocess.check_output("grep " + search + " tmp", shell=True)
运行终端命令时,我知道可以使用try/except捕获错误,但如何获取错误代码的值呢?
我在官方文档中找到了以下内容:

要运行终端命令,请使用subprocess模块。你可以使用check_output()函数获取返回值,并且如果有错误发生,会抛出CalledProcessError异常,其中包含错误代码。


 exception subprocess.CalledProcessError

    Exception raised when a process run by check_call() or check_output() returns a non-zero exit status.

    returncode

        Exit status of the child process.

但是没有给出任何例子,并且谷歌也没有提供帮助。

6个回答

98

您可以从引发的异常中获取错误代码和结果。

这可以通过字段returncodeoutput完成。

例如:

import subprocess

try:
    grepOut = subprocess.check_output("grep " + "test" + " tmp", shell=True)                       
except subprocess.CalledProcessError as grepexc:                                                                                                   
    print("error code", grepexc.returncode, grepexc.output)

4
谢谢,这正是我想要的。但现在我在想,是否有一种方法可以不使用try/except获取返回代码?也就是说,只需获取check_output的返回代码,无论是0还是1或其他值对我来说都不重要,实际上我并不需要保存输出内容。 - Juicy
5
没问题。不幸的是,只要错误代码非零,check_output函数总会抛出CalledProcessError异常。这意味着如果你不想程序突然终止,你需要使用try/except语句。然而,如果你不关心错误代码,当进入except子句时,你可以简单地使用"pass"语句。 - DanGar

47

Python 3.5 引入了 subprocess.run() 方法。方法签名如下:

subprocess.run(
  args, 
  *, 
  stdin=None, 
  input=None, 
  stdout=None, 
  stderr=None, 
  shell=False, 
  timeout=None, 
  check=False
)
返回的结果是 subprocess.CompletedProcess 对象。在3.5版本中,你可以访问执行进程的argsreturncodestdoutstderr
示例:
>>> result = subprocess.run(['ls', '/tmp'], stdout=subprocess.DEVNULL)
>>> result.returncode
0

>>> result = subprocess.run(['ls', '/nonexistent'], stderr=subprocess.DEVNULL)
>>> result.returncode
2

1
我认为这是最新的方法。语法更简单直观,很可能就是为了这个原因而添加的。 - dnk8n
1
根据 https://docs.python.org/3/library/subprocess.html#subprocess.run: "If check is true, and the process exits with a non-zero exit code, a CalledProcessError exception will be raised. Attributes of that exception hold the arguments, the exit code, and stdout and stderr if they were captured." - EchoLynx

37

是否有一种方法可以在没有try/except的情况下获取返回码?

check_output如果收到非零的退出状态,会引发异常,因为这通常意味着命令失败了。即使没有错误,grep也可能返回非零的退出状态 - 在这种情况下,您可以使用 .communicate()

from subprocess import Popen, PIPE

pattern, filename = 'test', 'tmp'
p = Popen(['grep', pattern, filename], stdin=PIPE, stdout=PIPE, stderr=PIPE,
          bufsize=-1)
output, error = p.communicate()
if p.returncode == 0:
   print('%r is found in %s: %r' % (pattern, filename, output))
elif p.returncode == 1:
   print('%r is NOT found in %s: %r' % (pattern, filename, output))
else:
   assert p.returncode > 1
   print('error occurred: %r' % (error,))

您不需要调用外部命令来筛选行,可以使用纯Python进行操作:

with open('tmp') as file:
    for line in file:
        if 'test' in line:
            print line,

如果您不需要输出,则可以使用 subprocess.call()

import os
from subprocess import call
try:
    from subprocess import DEVNULL # Python 3
except ImportError: # Python 2
    DEVNULL = open(os.devnull, 'r+b', 0)

returncode = call(['grep', 'test', 'tmp'], 
                  stdin=DEVNULL, stdout=DEVNULL, stderr=DEVNULL)

4

1
请阅读 https://stackoverflow.com/help/how-to-answer 了解如何撰写一个好的答案。 - DjSh
2
完成了。现在怎么办? - simfinite
不仅仅是阅读,更重要的是在你的答案中实现它。 - DjSh
4
我想我只是看不出哪里有问题。请告诉我你认为应该如何改进它。 - simfinite
1
你可以提供一个使用你所提到的方法的例子。然而,你的回答让我注意到了另一种我还不知道的方法,所以它已经对我很有价值了。 - derpedy-doo

2
在 Python 2 中 - 使用 commands 模块:
import command
rc, out = commands.getstatusoutput("ls missing-file")
if rc != 0: print "Error occurred: %s" % out

在Python 3中,使用subprocess模块:
import subprocess
rc, out = subprocess.getstatusoutput("ls missing-file")
if rc != 0: print ("Error occurred:", out)

发生错误:ls: 无法访问 missing-file: 没有那个文件或目录。

这是最佳选择。如果在机器上找不到命令(例如 nvcc),subprocess.run() 可能会抛出异常。这种方法将隐藏所有这些并在 returncode 中不抛出异常。 - Mahyar Mirrashed

1
请注意,自Python 3.5版本以后,最好使用subprocess.run()函数。
import subprocess

grepOut = subprocess.run(['grep', search, 'tmp'], shell=True) ## Only use shell=True if necessary

这将生成一个`subprocess.CompletedProcess`实例,该实例将存储在`grepOut`中。最后,回答你的问题,你可以通过以下方式获取`subprocess.run()`的返回值:
grepOut.returncode

如果命令成功,返回值将等于0,否则不等于0。
最后,为了完整起见,您甚至可以通过使用subprocess.CompletedProcess类的方法check_returncode()来处理错误,使用try/except块:
try:
    ## Add argument `capture_output=True` if you want to store the output of the command
    grepOut = subprocess.run(['grep', search, 'tmp'], shell=True)
    grepOut.check_returncode()

except subprocess.CalledProcessError as err:
    ## If returncode is non-zero, raise a CalledProcessError and print this message
    print(f"Oops, something went wrong. Error code: {err.returncode}")

希望这足够清楚。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接