繁体   English   中英

为什么在使用 subprocess.run() 时会抛出两个异常?

[英]Why are two exceptions thrown when using subprocess.run()?

我正在使用 python subprocess.run() 来处理一些命令。 我想捕获输出/错误/返回代码,并希望在命令被阻止时超时。 代码很简单:

cmd = "ping 1.1.1.1 -n 5"
subprocess.run(cmd, shell=True, timeout=2)

但是结果让我很困惑,为什么会抛出两个异常?

Python 3.6.8 (default, Jan 14 2019, 11:02:34) 
[GCC 8.0.1 20180414 (experimental) [trunk revision 259383]] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import subprocess
>>> cmd = "ping 1.1.1.1 -n 5"
>>> subprocess.run(cmd, shell=True, timeout=2)
PING 5 (0.0.0.5) 56(124) bytes of data.
Traceback (most recent call last):
  File "/usr/lib/python3.6/subprocess.py", line 425, in run
    stdout, stderr = process.communicate(input, timeout=timeout)
  File "/usr/lib/python3.6/subprocess.py", line 863, in communicate
    stdout, stderr = self._communicate(input, endtime, timeout)
  File "/usr/lib/python3.6/subprocess.py", line 1560, in _communicate
    self.wait(timeout=self._remaining_time(endtime))
  File "/usr/lib/python3.6/subprocess.py", line 1469, in wait
    raise TimeoutExpired(self.args, timeout)
subprocess.TimeoutExpired: Command 'ping 1.1.1.1 -n 5' timed out after 1.999514610040933 seconds

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python3.6/subprocess.py", line 430, in run
    stderr=stderr)
subprocess.TimeoutExpired: Command 'ping 1.1.1.1 -n 5' timed out after 2 seconds
>>> 

您没有处理 subprocess.run() 的异常。 子流程的Python 文档包含一个类似的示例,它还显示了回溯:

>>> subprocess.run("exit 1", shell=True, check=True)
Traceback (most recent call last):
  ...
subprocess.CalledProcessError: Command 'exit 1' returned non-zero exit status 1

因为您没有处理异常,所以 python 会在失败时为您提供回溯。 由于您是有意寻找异常 (TimeoutExpired),因此您需要处理它。 这是您的命令的示例:

import sys
import subprocess

f = open('output.txt', 'w') # store stdout
g = open('error.txt', 'w') # store stderr

cmd = "ping 8.8.8.8 -n -c 5"

try:
    subprocess.run(cmd, shell=True, check=False, stdout=f, stderr=g timeout=2)
except subprocess.TimeoutExpired as t:
    print("Timeout expired!")
    print(t.timeout)

来自这个的output是:

Timeout expired!
2

2 是超时阈值——subprocess.TimeoutExpired有其他你可以打印的属性:

cmd
    Command that was used to spawn the child process.
timeout
    Timeout in seconds.
output
    Output of the child process if it was captured by run() or check_output(). Otherwise, None.
stdout
    Alias for output, for symmetry with stderr.
stderr
    Stderr output of the child process if it was captured by run(). Otherwise, None.

我在我的本地目录中创建了 output.txt 和 error.txt 来捕获 stdout 和 stderr,这回答了你的另一部分问题,如何记录命令的 output 和错误以及超时。

如果您想要一定数量的 ping,则选项为“c”。 如果您希望 ping 命令超时,则选项为“w”。

>>> subprocess.run("ping -w 3 127.0.0.1".split())
PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.100 ms
64 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.125 ms
64 bytes from 127.0.0.1: icmp_seq=3 ttl=64 time=0.052 ms

--- 127.0.0.1 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2000ms
rtt min/avg/max/mdev = 0.052/0.092/0.125/0.031 ms
CompletedProcess(args=['ping', '-w', '3', '127.0.0.1'], returncode=0)

包装在 try/except 中意味着是否有多个异常无关紧要:

>>> try:
...   subprocess.run("ping 127.0.0.1".split(), timeout=2)
... except subprocess.TimeoutExpired:
...   print('handle')
... 
PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.094 ms
64 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.163 ms
handle

我遇到过类似的问题。 但我自己造成的 - 代表好的 IDE 建议:-D。 我已经正确处理了 TimeoutExpired,但在 except 块的末尾,我引发了另一个异常并使用from 它也上升了 TimeoutExpired,但没有再次处理。

try:
    check_output(...)
except subprocess.TimeoutExpired as problem:
    # some logging stuff
    raise ConnectionError("Some useful info") from problem

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM