Python无法从subprocess.check_call获取原始二进制数据

6

我该如何让subprocess.check_call命令返回一个命令的原始二进制输出?它似乎在某个地方对其进行了错误编码。

细节:

我有一个返回以下文本的命令:

some output text “quote” ...

以下是我如何调用该命令的方式:

f_output = SpooledTemporaryFile()
subprocess.check_call(cmd, shell=True, stdout=f_output)
f_output.seek(0)
output = f_output.read()

问题是我得到了这个:
>>> repr(output)
some output text ?quote? ...
>>> type(output)
<str>

(如果我将'ord'称为'?',我会得到63。)我在Linux上使用Python 2.7。请注意:在OSX上运行相同的代码对我来说是正确的。问题出现在我在Linux服务器上运行它时。

1
我写了一个快速的Python程序,它输出了UTF-8字符串,而你的程序对我有效。 - tdelaney
另一种思考方式是,由于Python 2.7读取了一个ASCII ?,它在被读取的文件中。因此,程序没有写入您认为它写入的字符串。 - tdelaney
@tdelaney,你在OSX上试过吗?在我的OSX上它实际上可以正常工作。我会更新我的问题。当我直接运行命令行时,它会将我写的内容打印到控制台上。我可以尝试将其重定向到文件,但我不知道那会显示什么。 - Greg
@tdelaney,我想你是对的,它可能不是发生在读取步骤中,而是当 check_call 捕获 stdout 并将其写入该文件时。 - Greg
在Linux中运行Python2代码f_output = SpooledTemporaryFile();subprocess.check_call('echo -e \'some output text \\xe2\\x80\x9cquote\\xe2\\x80\\x9d ...\'', shell=True, stdout=f_output);f_output.seek(0);output=f_output.read();print(repr(output));将得到'some output text \xe2\x80\x9cquote\xe2\x80\x9d ...\n' - v7d8dpo4
显示剩余3条评论
2个回答

1

哇,这是最奇怪的问题,但我已经解决了!

原来是调用的程序(一个Java程序)返回的编码取决于调用它的位置!

在Dev osx机器上,字符正常返回,在Linux服务器从命令行返回也正常,在Django应用程序中调用时,变成了“?”。

为了解决这个问题,我最终添加了这个参数到命令:

-Dfile.encoding=utf-8

我在这里得到了那个想法,它似乎有效。还有一种方法可以在Java程序内部进行修改。

抱歉我责怪了Python!你们的想法是正确的。


你尝试过按照我的建议修复你的区域设置(locale.getpreferredencoding())吗?(在你想要运行代码的上下文中检查它们) - jfs

0

重定向 (stdout=file) 是在文件描述符级别上进行的。如果您在文件本身中看到 ? 而不是 ,那么 Python 与写入文件无关。

如果它在 OS X 上工作而在 Linux 服务器上“不起作用”,则可能的原因是环境的差异,请检查 LC_ALL、LC_CTYPE、LANG 环境变量 - python、/bin/sh (由于 shell=True) 和 cmd 可能会使用您的区域编码,如果环境未设置,则为 ASCII (C、POSIX 区域设置)。

从子进程获取“原始二进制”:

#!/usr/bin/env python
import subprocess

raw_binary = subprocess.check_output(['cmd', 'arg 1', 'arg 2'])
print(repr(raw_binary))

注意:

  • 不要使用shell=True,除非必要。
  • 许多程序可能会改变它们的行为,如果它们检测到输出不是tty,例如

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接