python - 如何检查来自子进程的 Popen 是否抛出错误
问题描述
我正在编写一个以特定顺序使用一堆 bash 调用的管道。
如何判断我的命令是否引发错误?
例如,我正在运行一个带有子进程的 Java 程序,当这个进程出错时它不会警告我或退出。
我的对象中subprocess
或process
对象中是否有具有此实用程序的东西?
process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
process.wait()
当我尝试Python 的建议时:“subprocess.Popen”检查成功和错误时,我收到以下错误:
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
解决方案
两者check_call
和check_output
都应该传递要由命令系统运行的命令列表(将发送到的命令列表相同Popen
)。这两个都是阻塞调用,这意味着 Python 将等到它们完成运行更多代码。
UsingPopen
将命令列表发送到命令系统,但不会阻止 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, which generates an 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
如果命令系统的返回码不是 0,将引发 Python 异常。
# 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_output
非常相似,check_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
推荐阅读
- python-3.x - 如何使用 Python 中的 tabula 库从 pdf 中提取所有表格?
- hyperledger-fabric - Composer 网络启动超时
- angular - qz-tray sha-256 未定义
- python - 在 Lark 语法中正确设置规则和终端之间的优先级
- r - R 的传单:在弹出窗口中显示多个数据行
- node.js - Mongoose 到 JSON 并返回到 Mongoose 文档
- android - 尝试运行我的 Espresso 测试时 RecyclerViewMatcher 中的 NullPointerException
- c# - 实体框架到包含另一个对象列表的自定义对象
- ruby - 从 IO#pipe 获得的写入流的数据大小
- redux - 还原。如何使用 redux-saga 在 sagaMiddleWare.run([ f1*(), f2*(), f3*() ]) 中运行几个 saga?