Por que Popen.communicate () retorna b'hi \ n 'em vez de' hi '?


95

Alguém pode explicar por que o resultado que desejo, "oi", é precedido pela letra 'b' e seguido por uma nova linha?

Estou usando Python 3.3

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

Este 'b' extra não aparece se eu executá-lo com o python 2.7


1
Qual versão do Python você está usando?
Necrólito 2

2
Não tenho certeza sobre o 'b', mas a nova linha é porque echo hiimprime hi\r\n. Para evitar isso, você pode adicionar .strip () no final, ou uma correção semelhante.
azhrei

7
você poderia usar em check_output()vez de .communicate()aqui:print(subprocess.check_output("echo hi", shell=True, universal_newlines=True), end="")
jfs

Respostas:



95

O bindica que o que você tem é bytesuma sequência binária de bytes, em vez de uma string de caracteres Unicode. Subprocessa bytes de saída, não caracteres, então é isso que communicate()está retornando.

O bytestipo não print()pode ser diretamente ativado, então você está sendo mostrado o reprde que bytesvocê tem. Se você souber a codificação dos bytes recebidos do subprocesso, poderá usá decode()-los para convertê-los em um imprimível str:

>>> print(b'hi\n'.decode('ascii'))
hi

É claro que este exemplo específico só funciona se você realmente estiver recebendo ASCII do subprocesso. Se não for ASCII, você receberá uma exceção:

>>> 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…

A nova linha é parte do que echo hitem saída. echoO trabalho de é produzir os parâmetros que você passa, seguido por uma nova linha. Se não estiver interessado em espaços em branco ao redor da saída do processo, você pode usar da seguinte strip()forma:

>>> b'hi\n'.strip()
b'hi'

1
Como você faz com que a função print () imprima uma string de bytes sem um 'b' precedente? Ou você precisa primeiro convertê-lo em uma string Unicode?
imagineerThat

Estou curioso, quando os.popenretorna strings de texto, se há uma maneira de fazer subprocess.Popentambém retorná-los, em vez de strings de byte.
Pavel Šimerda

11
Vou responder a mim mesmo, há uma opção com um nome críptico chamado universal_newlinesque faz com que o Popenobjeto aceite e retorne strings de texto.
Pavel Šimerda

3
@ PavelŠimerda Embora os.popen retorne strings de texto, eles aparentemente estão sendo decodificados incorretamente para caracteres não ASCII, pelo menos no Windows. Por exemplo check_output("dir"), executar , extrair um nome de arquivo da saída e tentar acessá-lo com openfalhará se o nome do arquivo contiver tremas alemães. Pode ser um bug.
kdb

61

Conforme mencionado antes, echo hirealmente retorna hi\n, o que é um comportamento esperado.

Mas provavelmente você deseja apenas obter os dados em um formato "correto" e não lidar com a codificação. Tudo que você precisa fazer é passar a universal_newlines=Trueopção de subprocess.Popen()gostar assim:

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

Desta forma Popen(), substituirá esses símbolos indesejados por si só.


11
universal_newlines=Truefuncionou como um encanto. Esta deve ser a resposta aceita, na minha humilde opinião ...
Ethan Strider

3
Produz linhas vazias extras.
LoMaPh

1
Você pode precisar tanto universal_newlines=True em Popen(para se livrar do b'') e um strip()na cadeia resultante, se você quiser cortar a nova linha de terminação.
arielf

Para sua informação, a documentação diz que universal_newlinesagora é apenas um alias compatível com versões anteriores para o textparâmetro, que é mais claro, mas apenas no Python 3.7 e superior.
Harry Cutts

Ele produz linhas vazias extras porque não funciona. universal_newlines não remove \ n
kol23

8

b é a representação de byte e \ n é o resultado da saída de eco.

A seguir irá imprimir apenas os dados do resultado

import subprocess
print(subprocess.Popen("echo hi", shell=True,stdout=subprocess.PIPE).communicate()[0].decode('utf-8').strip())
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.