python - 管道传输到文件时,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")
解决方案
根本原因在于 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 中的文件,如果这样文件采用其他编码,您会收到错误,最好的情况是您会收到垃圾文本,最坏的情况是您会收到编码异常。
要解决它,您需要知道您的输入文件是使用哪种编码创建的,这可能会变得棘手并且检测通常很慢,其他解决方案是以字节为单位处理文件,但这可能无法实现,具体取决于完成的处理。
推荐阅读
- javascript - Puppeteer 单击提交按钮并打开新选项卡
- javascript - 如何编写条件以忽略某些代码
- swift - 为什么 LazyVGrid 的详细视图没有在 iPad 上更新
- c# - 我的视图模型没有填充管理区域内的视图
- javascript - Literallycanvas 按钮不可点击。能够加载 UI,但默认情况下只有铅笔在工作,并且在现有的 Angular 9 应用程序中没有其他图标
- javascript - 导航到另一个页面后来自 Testcafe 的奇怪行为
- linux - /etc/nginx/sites-available/wordpress 中的 Linux 脚本
- mysql - 在 Prisma 中创建或更新一对多关系
- c - 为什么这个循环遍历二维数组不起作用
- android - 如何防止特定视图在 Android 布局更改时被动画化?