为什么Popen.communicate()返回b'hi\n'而不是'hi'?

131 投票
4 回答
124482 浏览
提问于 2025-04-17 18:52

有人能解释一下为什么我想要的结果“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'就不会出现。

4 个回答

101

之前提到过,echo hi 实际上会返回 hi\n,这是正常的行为。

不过你可能只是想要以“正确”的格式获取数据,而不想处理编码问题。你只需要在调用 subprocess.Popen() 时加上 universal_newlines=True 这个选项,像这样:

>>> import subprocess
>>> print(subprocess.Popen("echo hi",
                           shell=True,
                           stdout=subprocess.PIPE,
                           universal_newlines=True).communicate()[0])
hi

这样一来,Popen() 就会自动替换掉这些不需要的符号。

122

这里的 b 表示你得到的是 bytes,也就是一串二进制数据,而不是一串Unicode字符。子进程输出的是字节,而不是字符,所以 communicate() 返回的就是这些字节。

bytes 类型不能直接用 print() 打印,所以你看到的是这些字节的 repr(表示形式)。如果你知道从子进程接收到的字节的编码方式,可以用 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'
28

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

撰写回答