【问题标题】:Python - Get command output cannot be decodedPython - 无法解码获取命令输出
【发布时间】:2021-05-31 12:55:11
【问题描述】:

我目前正在做一个项目,我需要在 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

尝试在另一台计算机上运行它,这是输出:

?????

知道为什么会这样,我该如何解决?尝试了很多我在其他问题上看到的东西,但没有一个对我有用。

【问题讨论】:

  • 尝试使用decode()encoding参数,例如decode(encoding="latin1")
  • 输出字符编码取决于您的 system/os/shell 设置。如果您收到 UnicodeDecodeError,则表示捕获的输出是 NOT unicode。您也许可以使用locale.getpreferredencoding() 获取编码并将其用作decode() 的参数,正如@Marino 上面指出的那样。
  • @Marino Latin-1 不支持希伯来语。解码会成功(因为任何字节序列都可以用Latin-1解码),但结果可能是垃圾。
  • 感谢您的 cmets。不幸的是 - 它们都不起作用:(我认为python中的命令输出实际上是字符?,不太清楚为什么。
  • 您能否提供一些您遇到问题的示例文件名?

标签: python powershell utf-8 decode


【解决方案1】:

注意:以下 Python 3+ 解决方案原则上可以工作,但是

  • 由于powershell.exe 中的一个错误,Windows PowerShell CLI当前控制台窗口切换到光栅字体(可能与不同的字体大小),这 not 支持大多数非扩展 ASCII 范围的 Unicode 字符。虽然视觉上不和谐,这只是一个显示(渲染)问题;数据处理正确;切换回可识别 Unicode 的字体(例如 Consolas)会显示正确的输出。

  • 相比之下,pwsh.exePowerShell (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 的输出并不是绝对必要的,但如果您想从 Python 传递该输出 on 则很重要:Python 3.x 默认为活动用于编码 非控制台 输出的 ANSI(!) 代码页,这意味着例如希伯来语字符不能在非控制台输出中表示(例如,在重定向到 文件时 em>),并导致脚本中断。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-06-18
    • 1970-01-01
    • 2016-03-09
    • 2011-05-21
    • 2016-10-03
    • 2013-08-21
    • 2013-09-06
    • 1970-01-01
    相关资源
    最近更新 更多