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

时间:2019-06-23 21:03:39

标签: python python-3.x

我正在使用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
>>> 

2 个答案:

答案 0 :(得分:1)

您没有处理subprocess.run()的异常。 Python documentation for subprocess包含一个类似的示例,并且还显示了回溯:

>>> 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)

输出是:

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,这回答了您询问的另一部分,如何记录命令的输出和错误以及超时。

答案 1 :(得分:0)

如果您想要一定数量的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