【问题标题】:Subprocess command encoding子进程命令编码
【发布时间】:2020-02-19 16:50:09
【问题描述】:

我目前正在将脚本从 Perl 迁移到 Python3 (3.6.5)。正在 Windows Server 2016 上运行。脚本使用参数构建命令行并使用 subprocess.check_output 执行创建的字符串。其中一个参数选项称为-location:"my street"。该位置可以包含特殊字符,例如变音符号 (äöß) 或 (áŠ)。

当我运行 Perl 脚本时,特殊字符会正确传递给应用程序。当我运行 Python 脚本时,特殊字符被应用程序中的问号替换。我认为被调用的应用程序需要一个 UTF-8 编码的参数字符串。

Perl 脚本以 UTF-8 模式运行

use UTF8;
binmode( STDOUT, ":utf-8" );

Python 脚本是用 PyCharm 创建的,UTF-8 编码,脚本的第一行包含

# -*- coding: utf-8 -*-

我尝试了几种方法将子进程参数的编码设置为 UTF-8,但没有奏效。我使用procmon.exe 来比较Perl 和Python 脚本之间的应用程序调用。我可以看到,在 procmon 中为 Python 子进程调用显示的命令行对我来说是可读的。工作的 Perl 调用不是。在 procmon 中查找 perl 脚本的位置字符串如下所示:

-location:"HQ/äöööStraße".

Perl 代码如下所示:

$command = "C:\\PROGRAM FILES\\Application\\bin\\cfg.exe"
$operand = "-modify -location:123á456ß99"
$result  = `$command $operand`;

Python 代码如下所示:

# -*- coding: utf-8 -*-
import subprocess
result = subprocess.check_output(['C:\\PROGRAM FILES\\Application\\bin\\cfg.exe', "-modify", "-location:123á456ß99"], shell=False, stderr=subprocess.STDOUT)

知道我必须做什么才能将 python 参数正确传递给应用程序吗?

【问题讨论】:

  • 你真的希望stderr 包含stdout吗?
  • 你试过loc_str.encode('utf-8')。这里loc_str 是带有该位置参数的字符串,然后传递给子进程

标签: python python-3.x perl


【解决方案1】:

在 Python 3.3+ 中,您可以单独指出您希望文本采用特定编码。关键字参数 universal_newlines=True 在 3.7 中重命名为更准确和透明的 text=True

这个关键字基本上说“只使用我系统上默认的任何编码”(所以基本上是 UTF-8 在任何相当现代的东西上,除了在 Windows 上,你会得到 一些来自深渊的 Cthulhu 暴行默认代码页)。

在没有此关键字的情况下,子进程在 Python 3 中接收并返回 bytes

当然,如果你知道编码,你也可以单独.decode()bytes你回来。

如果您知道编码,使用 encoding= 关键字参数可能很有用(即使您假设它也是系统编码;这是在 Python 3.6 中添加的)。

response = subprocess.check_output([...], text=True)
response = subprocess.check_output([...], encoding='utf-8')
response = subprocess.check_output([...]).decode('utf-8')

【讨论】:

  • 更多(更多)信息,请参见stackoverflow.com/questions/4256107/…
  • 我测试了所有三个选项。结果与没有这个关键字的结果相同。没有改进。
  • 那么你得到了什么?崩溃?还是垃圾数据(究竟是什么数据)?
  • 我的问题不是我得到的结果。它是传递给我用子进程调用的应用程序的参数。特殊字符在 procmon 中仍然是可读的,并且不像 perl 那样编码。
  • 所以您希望"-location:123á456ß99" 以UTF-8 格式传递给进程?你的系统编码是什么?
【解决方案2】:

让脚本运行的诀窍是将参数编码为“utf8”,然后将它们解码为“ansi”。

command = r'C:\PROGRAM FILES\Application\bin\cfg.exe'
argument = ["-modify", "-location:123á456ß99"]

argument_ansi = []
for x in argument:
    argument_ansi.append(x.encode('utf-8').decode('ansi', 'replace'))
cmd = [command]
cmd.extend(argument_ansi)
result = subprocess.check_output(cmd, shell=False, encoding="utf-8", universal_newlines=True)

【讨论】:

    猜你喜欢
    • 2014-03-26
    • 2021-12-10
    • 2018-08-15
    • 1970-01-01
    • 2017-01-09
    • 2014-06-13
    • 2020-11-26
    • 2012-10-31
    • 1970-01-01
    相关资源
    最近更新 更多