当我将子进程与 check=True 一起使用时,如何获得错误消息

How can I get error messages when I use subprocess with check=True

我刚刚意识到如果我在子进程中使用 check=True,我不会得到 CompletedProcess 描述符。这看起来像是一个设计缺陷:如何获取被调用程序发送的错误消息?

显然还有其他方法可以获取我程序的 return 代码,但这里的重点是 check=True 参数似乎与错误处理不兼容。

还是我漏掉了什么?

#!/usr/bin/python3

import subprocess
import sys

subproc1 = subprocess.run('ls /nonexistent', stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, shell=True)
print(subproc1.stderr, file=sys.stderr, end='', flush=True)
print(subproc1.stdout, file=sys.stdout, end='', flush=True)
print('▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔', file=sys.stderr, flush=True)


try: subproc2 = subprocess.run('ls /', stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, shell=True, check=True)
except subprocess.CalledProcessError:
    print("FAIL")
    print(subproc2.stderr, file=sys.stderr, end='', flush=True)
    print(subproc2.stdout, file=sys.stdout, end='', flush=True)
    print('▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔', file=sys.stderr, flush=True)
    raise
else:
    print("GOOD")
    print(subproc2.stderr, file=sys.stderr, end='', flush=True)
    print(subproc2.stdout, file=sys.stdout, end='', flush=True)
    print('▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔', file=sys.stderr, flush=True)


try: subproc3 = subprocess.run('ls /nonexistent', stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, shell=True, check=True)
except subprocess.CalledProcessError:
    print("FAIL")
    print(subproc3.stderr, file=sys.stderr, end='', flush=True)
    print(subproc3.stdout, file=sys.stdout, end='', flush=True)
    print('▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔', file=sys.stderr, flush=True)
    raise
else:
    print("GOOD")
    print(subproc3.stderr, file=sys.stderr, end='', flush=True)
    print(subproc3.stdout, file=sys.stdout, end='', flush=True)
    print('▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔', file=sys.stderr, flush=True)

产量:

ls: cannot access '/nonexistent': No such file or directory
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
GOOD
bin
[...]
var
vmlinuz
vmlinuz.old
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
FAIL
Traceback (most recent call last):
  File "/root/subprocess_error.py", line 27, in <module>
    try: subproc3 = subprocess.run('ls /nonexistent', stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, shell=True, check=True)
  File "/usr/lib/python3.7/subprocess.py", line 487, in run
    output=stdout, stderr=stderr)
subprocess.CalledProcessError: Command 'ls /nonexistent' returned non-zero exit status 2.

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/root/subprocess_error.py", line 30, in <module>
    print(subproc3.stderr, file=sys.stderr, end='', flush=True)
NameError: name 'subproc3' is not defined

捕获的内容保存到异常本身。

将异常对象分配给一个变量,并从中读取 .stdout.stderr

import subprocess
import sys

try:
    subproc3 = subprocess.run('ls /nonexistent', stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, shell=True, check=True)
except subprocess.CalledProcessError as ex:
    print("FAIL")
    print(ex.stderr, file=sys.stderr, end='', flush=True)
    print(ex.stdout, file=sys.stdout, end='', flush=True)