Python - 获取命令输出无法解码
Python - Get command output cannot be decoded
我目前正在做一个项目,我需要在 powershell 中 运行 一个命令,并且部分输出不是英语(特别是希伯来语)。
例如(问题的简化版),如果我想获取桌面的内容,并且有希伯来文的文件名:
import subprocess
command = "powershell.exe ls ~/Desktop"
print (subprocess.run(command.split(), stdout=subprocess.PIPE).stdout.decode())
此代码将引发以下错误(或具有不同字节值的类似错误):
UnicodeDecodeError: 'utf8' codec can't decode byte 0x96 in position 19: invalid start byte
试图在另一台计算机上 运行 它,这是输出:
?????
知道这是为什么吗?我该如何解决?尝试了很多我在其他问题上看到的东西,但 none 对我有用。
注意:以下Python 3+ 解决方案在原则上有效,但是:
由于powershell.exe
中的错误,Windows PowerShell CLI,当前控制台window 切换到光栅字体(可能具有不同的字体大小),不支持大多数非扩展 ASCII -range Unicode 字符。尽管在视觉上很刺耳,这只是一个 显示(渲染)问题;数据处理正确;切换回 Unicode 识别字体,例如 Consolas
会显示正确的输出。
相比之下,pwsh.exe
,PowerShell (Core) (v6+) CLI不是 出现这个问题.
选项 A:配置控制台 和 Python 以使用 UTF-8 字符编码在 执行您的脚本之前:
配置控制台使用UTF-8:
从 cmd.exe
,通过将活动的 OEM 代码页切换到 65001
(UTF-8);请注意,此更改可能会影响会话中所有以后对控制台应用程序的调用,与 Python 无关,除非您恢复原始代码页(请参阅下面的选项 B):
chcp 65001
来自 PowerShell:
$OutputEncoding = [Console]::InputEncoding = [Console]::OutputEncoding = [System.Text.UTF8Encoding]::new()
配置 Python (v3+) 以一致地使用 UTF-8 :[1]
通过注册表将环境变量PYTHONUTF8
设置为1
,可能持久;这样做 临时:
来自 cmd.exe
:
Set PYTHONUTF8=1
来自 PowerShell:
$env:PYTHONUTF8=1
或者,对于单个调用 (v3.7+):将命令行选项 -X utf8
传递给 python
解释器(注意:区分大小写):
python -X utf8 somefile.py ...
现在,您的原始代码应该按原样工作(显示错误除外)。
选项 B:暂时 为 PowerShell 调用切换到 UTF-8:
import sys, ctypes, subprocess
# Switch Python's own encoding to UTF-8, if necessary
# This is the in-script equivalent of setting environment var.
# PYTHONUTF8 to 1 *before* calling the script.
sys.stdin.reconfigure(encoding='utf-8'); sys.stdout.reconfigure(encoding='utf-8'); sys.stderr.reconfigure(encoding='utf-8')
# Enclose the PowerShell call in `chcp` calls:
# * Change to the UTF-8 code page (65001),
# * Execute the PowerShell command (which then outputs UTF-8)
# * Restore the original OEM code page.
command = "chcp 65001 >NUL & powershell ls ~/Desktop & chcp " + str(ctypes.cdll.kernel32.GetConsoleOutputCP()) + ' >NUL'
# Note:
# * `shell=True` ensure that the command is invoked via cmd.exe, which is
# required, now that we're calling *multiple* executables and use output
# redirections (`>NUL`)
print(subprocess.run(command.split(), stdout=subprocess.PIPE, shell=True).stdout.decode())
[1] 这对于正确解码 PowerShell 的输出并不是绝对必要的,但如果你想从 [=146 传递 on 的输出就很重要=]: Python 3.x 默认为编码 non-console 输出的活动 ANSI(!) 代码页,这意味着例如希伯来语字符不能在非控制台输出中表示(例如,当重定向到 文件 时),并导致脚本中断。
我目前正在做一个项目,我需要在 powershell 中 运行 一个命令,并且部分输出不是英语(特别是希伯来语)。
例如(问题的简化版),如果我想获取桌面的内容,并且有希伯来文的文件名:
import subprocess
command = "powershell.exe ls ~/Desktop"
print (subprocess.run(command.split(), stdout=subprocess.PIPE).stdout.decode())
此代码将引发以下错误(或具有不同字节值的类似错误):
UnicodeDecodeError: 'utf8' codec can't decode byte 0x96 in position 19: invalid start byte
试图在另一台计算机上 运行 它,这是输出:
?????
知道这是为什么吗?我该如何解决?尝试了很多我在其他问题上看到的东西,但 none 对我有用。
注意:以下Python 3+ 解决方案在原则上有效,但是:
由于
powershell.exe
中的错误,Windows PowerShell CLI,当前控制台window 切换到光栅字体(可能具有不同的字体大小),不支持大多数非扩展 ASCII -range Unicode 字符。尽管在视觉上很刺耳,这只是一个 显示(渲染)问题;数据处理正确;切换回 Unicode 识别字体,例如Consolas
会显示正确的输出。相比之下,
pwsh.exe
,PowerShell (Core) (v6+) CLI不是 出现这个问题.
选项 A:配置控制台 和 Python 以使用 UTF-8 字符编码在 执行您的脚本之前:
配置控制台使用UTF-8:
从
cmd.exe
,通过将活动的 OEM 代码页切换到65001
(UTF-8);请注意,此更改可能会影响会话中所有以后对控制台应用程序的调用,与 Python 无关,除非您恢复原始代码页(请参阅下面的选项 B):chcp 65001
来自 PowerShell:
$OutputEncoding = [Console]::InputEncoding = [Console]::OutputEncoding = [System.Text.UTF8Encoding]::new()
配置 Python (v3+) 以一致地使用 UTF-8 :[1]
通过注册表将环境变量
PYTHONUTF8
设置为1
,可能持久;这样做 临时:来自
cmd.exe
:Set PYTHONUTF8=1
来自 PowerShell:
$env:PYTHONUTF8=1
或者,对于单个调用 (v3.7+):将命令行选项
-X utf8
传递给python
解释器(注意:区分大小写):python -X utf8 somefile.py ...
现在,您的原始代码应该按原样工作(显示错误除外)。
选项 B:暂时 为 PowerShell 调用切换到 UTF-8:
import sys, ctypes, subprocess
# Switch Python's own encoding to UTF-8, if necessary
# This is the in-script equivalent of setting environment var.
# PYTHONUTF8 to 1 *before* calling the script.
sys.stdin.reconfigure(encoding='utf-8'); sys.stdout.reconfigure(encoding='utf-8'); sys.stderr.reconfigure(encoding='utf-8')
# Enclose the PowerShell call in `chcp` calls:
# * Change to the UTF-8 code page (65001),
# * Execute the PowerShell command (which then outputs UTF-8)
# * Restore the original OEM code page.
command = "chcp 65001 >NUL & powershell ls ~/Desktop & chcp " + str(ctypes.cdll.kernel32.GetConsoleOutputCP()) + ' >NUL'
# Note:
# * `shell=True` ensure that the command is invoked via cmd.exe, which is
# required, now that we're calling *multiple* executables and use output
# redirections (`>NUL`)
print(subprocess.run(command.split(), stdout=subprocess.PIPE, shell=True).stdout.decode())
[1] 这对于正确解码 PowerShell 的输出并不是绝对必要的,但如果你想从 [=146 传递 on 的输出就很重要=]: Python 3.x 默认为编码 non-console 输出的活动 ANSI(!) 代码页,这意味着例如希伯来语字符不能在非控制台输出中表示(例如,当重定向到 文件 时),并导致脚本中断。