首页 > 解决方案 > 管道传输到文件时,Powershell 中调用的 Python 脚本无法写入标准输出

问题描述

所以我试图将几个脚本链接在一起,一些在powershell(5.1)中,一些在python(3.7)中。

我遇到问题的脚本是用 python 编写的,并通过 sys.stdout.write() 写入标准输出。该脚本读入一个文件,完成一些处理,然后输出结果。

当这个脚本被自己调用时,也就是说没有输出到任何管道,它会正确执行并写入标准的 powershell 控制台。但是,一旦我尝试以任何方式管道输出,我就会开始出错。

特别是,两个文件具有字符 \u200b 或零宽度空格。将这些字符的输出打印到控制台很好,但尝试通过多种方法将输出重定向到文件:

py ./script.py input.txt > output.txt
py ./script.py input.txt | Set-Content -Encoding utf8 output.txt
Start-Process powershell -RedirectStandardOutput "output.txt" -Argumentlist "py", "./script.py", "input.txt"
$PSDefaultParameterValues['Out-File:Encoding'] = 'utf8'

都失败了:

File "\Python\Python37\lib\encodings\cp1252.py", line 19, in encode
    return codecs.charmap_encode(input,self.errors,encoding_table)[0]
UnicodeEncodeError: 'charmap' codec can't encode character '\u200b' in position 61: character maps to <undefined>

在python方面,修改脚本以删除所有非UTF-8字符也会导致这个脚本失败,所以我有点卡住了。我目前认为问题的发生是由于管道输出如何导致 python 设置不同的环境,但我不确定如何在 python 代码中进行此类修改。

为了完整起见,这里是编写输出的函数。(注意:file_lines 是一个字符串列表):

import sys

def write_lines(file_lines):
    for line in file_lines:
        line = list(map(lambda x: '"' + x + '"', line))
        line = "".join(entry + ',' for entry in line)
        if not line is None:
            sys.stdout.write(line + "\n")

标签: pythonpython-3.xpowershellio-redirectionzero-width-space

解决方案


根本原因在于 python 处理 STDOUT 的方式。Python 进行了一些低级检测以获取系统的编码,然后使用 aio.TextIOWrapper将编码设置为它检测到的内容,这就是您得到的内容sys.stdout(stderr 和 stdin 具有相同的内容)。

现在,此检测在 shell 中运行时返回 UTF-8,因为 powershell 在 UTF-8 中工作,并在系统和正在运行的程序之间放置了一层翻译,但是当管道到另一个程序时,通信是直接的,没有 powershell 翻译,这个直接通信使用系统的编码,对于 windows 是 cp1252 (AKA Windows-1252)。

system <(cp1252)> posh <(utf-8)> python # here stdout returns to the shell
system <(cp1252)> posh <(utf-8)> python <(cp1252)> pipe| or redirect> # here stdout moves directly to the next program

至于您的问题,不查看程序的其余部分和输入文件,我最好的猜测是一些编码不匹配,很可能是在读取输入文件时,默认情况下,python 3+ 将读取 utf-8 中的文件,如果这样文件采用其他编码,您会收到错误,最好的情况是您会收到垃圾文本,最坏的情况是您会收到编码异常。

要解决它,您需要知道您的输入文件是使用哪种编码创建的,这可能会变得棘手并且检测通常很慢,其他解决方案是以字节为单位处理文件,但这可能无法实现,具体取决于完成的处理。


推荐阅读