如何检查子进程中的Popen是否引发错误

时间:2019-01-15 23:42:22

标签: python bash shell command subprocess

我正在编写一个管道,该管道以特定顺序使用一堆bash调用。

如何确定我的命令是否抛出错误?

例如,我正在运行带有子进程的Java程序,当该进程出错时,它不会警告我或退出。

subprocess或我的process对象中是否有使用此实用程序的东西?

process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
process.wait()

当我尝试来自Python: "subprocess.Popen" check for success and errors的建议时,出现以下错误:

In [6]: subprocess.check_call(process)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-6-f8f8752a245f> in <module>
----> 1 subprocess.check_call(process)

~/anaconda/envs/µ_env/lib/python3.6/subprocess.py in check_call(*popenargs, **kwargs)
    284     check_call(["ls", "-l"])
    285     """
--> 286     retcode = call(*popenargs, **kwargs)
    287     if retcode:
    288         cmd = kwargs.get("args")

~/anaconda/envs/µ_env/lib/python3.6/subprocess.py in call(timeout, *popenargs, **kwargs)
    265     retcode = call(["ls", "-l"])
    266     """
--> 267     with Popen(*popenargs, **kwargs) as p:
    268         try:
    269             return p.wait(timeout=timeout)

~/anaconda/envs/µ_env/lib/python3.6/subprocess.py in __init__(self, args, bufsize, executable, stdin, stdout, stderr, preexec_fn, close_fds, shell, cwd, env, universal_newlines, startupinfo, creationflags, restore_signals, start_new_session, pass_fds, encoding, errors)
    707                                 c2pread, c2pwrite,
    708                                 errread, errwrite,
--> 709                                 restore_signals, start_new_session)
    710         except:
    711             # Cleanup if the child failed starting.

~/anaconda/envs/µ_env/lib/python3.6/subprocess.py in _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, start_new_session)
   1218                 args = [args]
   1219             else:
-> 1220                 args = list(args)
   1221
   1222             if shell:

TypeError: 'Popen' object is not iterable

In [7]: subprocess.check_output(process)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-7-0ec9e7eac1c2> in <module>
----> 1 subprocess.check_output(process)

~/anaconda/envs/µ_env/lib/python3.6/subprocess.py in check_output(timeout, *popenargs, **kwargs)
    334
    335     return run(*popenargs, stdout=PIPE, timeout=timeout, check=True,
--> 336                **kwargs).stdout
    337
    338

~/anaconda/envs/µ_env/lib/python3.6/subprocess.py in run(input, timeout, check, *popenargs, **kwargs)
    401         kwargs['stdin'] = PIPE
    402
--> 403     with Popen(*popenargs, **kwargs) as process:
    404         try:
    405             stdout, stderr = process.communicate(input, timeout=timeout)

~/anaconda/envs/µ_env/lib/python3.6/subprocess.py in __init__(self, args, bufsize, executable, stdin, stdout, stderr, preexec_fn, close_fds, shell, cwd, env, universal_newlines, startupinfo, creationflags, restore_signals, start_new_session, pass_fds, encoding, errors)
    707                                 c2pread, c2pwrite,
    708                                 errread, errwrite,
--> 709                                 restore_signals, start_new_session)
    710         except:
    711             # Cleanup if the child failed starting.

~/anaconda/envs/µ_env/lib/python3.6/subprocess.py in _execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, start_new_session)
   1218                 args = [args]
   1219             else:
-> 1220                 args = list(args)
   1221
   1222             if shell:

TypeError: 'Popen' object is not iterable

1 个答案:

答案 0 :(得分:1)

check_callcheck_output都应传递命令系统要运行的命令列表(与发送到Popen的命令列表相同)。这两个都阻止了调用,这意味着Python将等到它们完成运行更多代码之后。

使用Popen将命令列表发送到命令系统,但不阻止进一步执行Python代码。您可以使用.poll对象的Popen方法来检查过程,也可以使用.communicate进行阻塞调用,这将返回标准输出和标准错误流的元组。

假设您想要执行的命令的结果,并且该命令将向错误流正确报告错误,则可以使用:

process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = process.communicate()

if err:
     print('The process raised an error:', err.decode())

以下是一些示例:

使用Popen

import subprocess

# first a command that works correctly
proc = subprocess.Popen(['ls', '-a'], , stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = proc.communicate()
if not err:
    print('--No errors--\n', out.decode())
else:
    print('--Error--\n', err.decode())

# prints:
--No errors--
anaconda3
Desktop
Documents
Downloads

# next a command generates and error, the `-w` switch is invalid
proc = subprocess.Popen(['ls', '-w'], , stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = proc.communicate()
if not err:
    print('--No errors--\n', out.decode())
else:
    print('--Error--\n', err.decode())

# prints:
--Error--
 ls: option requires an argument -- 'w'
Try 'ls --help' for more information.

使用check_call

check_call将引发Python异常,如果命令系统的返回代码不为0。

# first with a working command:
ret_code = subprocess.check_call(['ls', '-a'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
ret_code
# returns:
0

# and now with the command that generates an error:
ret_code = subprocess.check_call(['ls', '-w'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)

# raises an exception:
---------------------------------------------------------------------------
CalledProcessError                        Traceback (most recent call last)
<ipython-input-25-3cd5107991a2> in <module>()
----> 1 ret_code = subprocess.check_call(['ls', '-w'], stdout=subprocess.PIPE, 
        stderr=subprocess.PIPE)

~/anaconda3/lib/python3.6/subprocess.py in check_call(*popenargs, **kwargs)
    289         if cmd is None:
    290             cmd = popenargs[0]
--> 291         raise CalledProcessError(retcode, cmd)
    292     return 0
    293

CalledProcessError: Command '['ls', '-w']' returned non-zero exit status 2.

要处理该异常,请使用try/except块。

try:
    ret_code = subprocess.check_call(['ls', '-w'], stdout=subprocess.PIPE, 
        stderr=subprocess.PIPE)
except subprocess.CalledProcessError as e:
    ret_code = e.returncode
    print('An error occurred.  Error code:', ret_code)

# prints:
An error occurred.  Error code: 2

使用check_output

check_outputcheck_call非常相似,如果命令系统的返回代码不为0,它将引发Python异常。但是,如果返回代码为0,则它​​将返回在标准输出流中输出。

# just with the error process this time
try:
    ret_code = subprocess.check_output(['ls', '-w'], stdout=subprocess.PIPE, 
        stderr=subprocess.PIPE)
except subprocess.CalledProcessError as e:
    ret_code = e.returncode
    print('An error occurred.  Error code:', ret_code)

# prints:
An error occurred.  Error code: 2