macOS 中 Python 子进程标准输出中出现 0xc3 的 UnicodeDecodeError

UnicodeDecodeError with 0xc3 in Python subprocess stdout in macOS

我正在开发一个 python 脚本来在 WSL 和 macOS 中编译 LaTeX 文件,但是当我在 macOS 中 运行 它时,它在子进程 stdout utf-8 编解码器中失败。但是,它适用于 WSL。 Python 两个版本都是 3.6

代码没有任何code/decode句,所以我认为问题出在子进程stdout的内部调用

def execute(cmd, pipe):
    if pipe:
        ps = subprocess.Popen(cmd, stdout=subprocess.PIPE)
        output = subprocess.check_output(pipe, stdin=ps.stdout, universal_newlines=True)
        print(colored(output, 'red'), file=sys.stderr)
        ps.wait()
    else:
        output = subprocess.call(cmd)
        print(colored(output, 'red'), file=sys.stderr)


start_time = time.time()
for cmd, pipe in zip(commands, pipes):
    print(colored(cmd, 'green'), file=sys.stderr)
    execute(cmd, pipe)

我得到的输出是

['pdflatex', '-shell-escape', '--interaction', 'nonstopmode', '-file-line-error', 'besolidary.tex']
Traceback (most recent call last):
  File "compile.py", line 61, in <module>
    execute(cmd, pipe)
  File "compile.py", line 50, in execute
    output = subprocess.check_output(pipe, stdin=ps.stdout, universal_newlines=True)
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/subprocess.py", line 336, in check_output
    **kwargs).stdout
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/subprocess.py", line 405, in run
    stdout, stderr = process.communicate(input, timeout=timeout)
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/subprocess.py", line 830, in communicate
    stdout = self.stdout.read()
  File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/codecs.py", line 321, in decode
    (result, consumed) = self._buffer_decode(data, self.errors, final)
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xc3 in position 1335: invalid continuation byte

在 WSL 中工作正常并抛出所有命令。

由于您指定了 universal_newlines=True,Python 隐含地期望来自子进程的 text-output。由于没有给 check_output() 编码,它默认为 locale.getpreferredencoding(False) 返回的编码;这恰好是 utf-8.

在你的例子中,子进程实际上并没有按照 Python 认为首选的编码方式对其输出进行编码,你在尝试这样做时会得到一个 DecodeError。

如果您确实希望从子进程获得 text-output,则需要一种方法来找出子进程将使用的编码(或强制其使用)。否则,如果输出实际上是二进制的,请将 universal_newlines 保留为默认值。