为啥 Popen.communicate() 返回 b'hi\n' 而不是 'hi'?
Posted
技术标签:
【中文标题】为啥 Popen.communicate() 返回 b\'hi\\n\' 而不是 \'hi\'?【英文标题】:Why does Popen.communicate() return b'hi\n' instead of 'hi'?为什么 Popen.communicate() 返回 b'hi\n' 而不是 'hi'? 【发布时间】:2013-02-28 17:34:44 【问题描述】:有人能解释一下为什么我想要的结果“hi”前面有一个字母“b”,后面有一个换行符吗?
我正在使用 Python 3.3
>>> import subprocess
>>> print(subprocess.Popen("echo hi", shell=True,
stdout=subprocess.PIPE).communicate()[0])
b'hi\n'
如果我使用 python 2.7 运行它,则不会出现这个额外的“b”
【问题讨论】:
你用的是什么版本的 Python? 不确定'b',但换行是因为echo hi
打印hi\r\n
。为避免这种情况,您可以在末尾添加 .strip() 或类似的修复。
你可以在这里使用check_output()
而不是.communicate()
:print(subprocess.check_output("echo hi", shell=True, universal_newlines=True), end="")
【参考方案1】:
b
表示您拥有的是bytes
,它是字节的二进制序列,而不是 Unicode 字符的字符串。子进程输出字节,而不是字符,这就是 communicate()
返回的内容。
bytes
类型不直接是 print()
able,因此您看到的是 repr
和 bytes
。如果您知道从子进程收到的字节的编码,则可以使用decode()
将它们转换为可打印的str
:
>>> print(b'hi\n'.decode('ascii'))
hi
当然,此特定示例仅在您实际从子进程接收 ASCII 时才有效。如果不是 ASCII,你会得到一个异常:
>>> print(b'\xff'.decode('ascii'))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xff in position 0…
换行符是echo hi
输出的一部分。 echo
的工作是输出你传递给它的参数,然后是一个换行符。如果您对进程输出周围的空白不感兴趣,可以使用strip()
,如下所示:
>>> b'hi\n'.strip()
b'hi'
【讨论】:
如何让 print() 函数打印一个没有前面的 'b' 的字节字符串?还是需要先转成unicode字符串? 我很好奇,当os.popen
返回文本字符串时,是否有办法让subprocess.Popen
也返回它们,而不是字节字符串。
我会回答自己,有一个名为 universal_newlines
的隐蔽名称选项会导致 Popen
对象接受并返回文本字符串。
@PavelŠimerda 虽然 os.popen 返回文本字符串,但它们显然被错误地解码为非 ascii 字符,至少在 Windows 上是这样。例如。运行check_output("dir")
,如果文件名包含德语变音符号,则从输出中提取文件名然后尝试使用open
访问它会失败。可能是一个错误。【参考方案2】:
如前所述,echo hi
实际上确实返回了hi\n
,这是预期的行为。
但您可能只想以“正确”的格式获取数据,而不是处理编码。您需要做的就是将universal_newlines=True
选项传递给subprocess.Popen()
,如下所示:
>>> import subprocess
>>> print(subprocess.Popen("echo hi",
shell=True,
stdout=subprocess.PIPE,
universal_newlines=True).communicate()[0])
hi
这样Popen()
将自行替换这些不需要的符号。
【讨论】:
universal_newlines=True
就像一个魅力。以我的拙见,这应该是公认的答案...
它会产生额外的空行。
你可能需要 both universal_newlines=True
in Popen
(摆脱b''
)和结果字符串上的strip()
,如果你想砍掉终止的换行符。
仅供参考,the documentation 说 universal_newlines
现在只是 text
参数的向后兼容别名,它更清晰但仅在 Python 3.7 及更高版本中。
它会产生额外的空行,因为它不起作用。 Universal_newlines 不删除\n【参考方案3】:
echo 命令默认返回换行符
比较一下:
print(subprocess.Popen("echo -n hi", \
shell=True, stdout=subprocess.PIPE).communicate()[0])
字符串前面的b表示它是一个字节序列,相当于Python 2.6+中的普通字符串
http://docs.python.org/3/reference/lexical_analysis.html#literals
【讨论】:
括号内不需要'\'。【参考方案4】:b 是字节表示,\n 是 echo 输出的结果。
以下将只打印结果数据
import subprocess
print(subprocess.Popen("echo hi", shell=True,stdout=subprocess.PIPE).communicate()[0].decode('utf-8').strip())
【讨论】:
以上是关于为啥 Popen.communicate() 返回 b'hi\n' 而不是 'hi'?的主要内容,如果未能解决你的问题,请参考以下文章
Python Popen communicate 和wait使用上的区别
如何使用子进程 Popen.communicate() 方法?
带有标准输入的 subprocess.Popen.communicate() 的管道损坏