Python - Get 命令输出无法解码

问题描述 投票:0回答:1

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

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

?????

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

python powershell utf-8 decode
1个回答
3
投票

注意:以下 Python 3+ 解决方案原则上有效,但是

  • 使用下面的第一个解决方案,由于powershell.exe

    中的错误,Windows PowerShellCLI当前控制台窗口切换到光栅字体(可能使用不同的字体)字体大小),它支持大多数非扩展 ASCII 范围的 Unicode 字符。虽然视觉上很刺耳,这只是一个显示(渲染)问题;数据处理正确;切换回支持 Unicode 的字体(例如 Consolas
    )会显示正确的输出。

  • 相比之下,

    pwsh.exe

    PowerShell(核心)(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 ...
      

    • 两个选项都启用
    • Python UTF-8 模式将成为 Python 3.15 中的默认模式

  • 现在,您的原始代码应该按原样工作(除了显示错误)。

注:

通过一次性配置步骤
    更简单的替代方案
  • 是将您的系统配置为 使用 UTF-8 系统范围,在这种情况下,OEM 和 ANSI 代码页都设置为 65001。然而,这会产生
    深远的影响
    - 请参阅这个答案

选项 B:(暂时)切换到 UTF-8 以进行 PowerShell 调用:

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') # Save the current console output code page and switch to 65001 (UTF-8) previousCp = windll.kernel32.GetConsoleOutputCP() windll.kernel32.SetConsoleOutputCP(65001) # PowerShell now emits UTF-8-encoded output; decode it as such. command = "powershell.exe ls ~/Desktop" print(subprocess.run(command, stdout=subprocess.PIPE).stdout.decode()) # Restore the previous output console code page. windll.kernel32.SetConsoleOutputCP(previousCp)

注:

由于仅设置了
    输出
  • 控制台页面,避免了Windows PowerShell显示错误 如果您还想将输入发送到 PowerShell 的
  • stdin
  • 流,则还必须通过 windll.kernel32.SetConsoleCP(65001) 设置 input 控制台页面(这将再次暴露显示错误)。
    
    

[1] 这对于正确解码 PowerShell 的输出来说并不是绝对必要的,但如果您想从 Python

on 传递该输出,则很重要:Python 3.x 默认使用活动的 ANSI(!) 代码页进行编码 非控制台输出,这意味着希伯来语字符无法在非控制台输出中表示(例如,重定向到文件时),并导致脚本中断。

© www.soinside.com 2019 - 2024. All rights reserved.