Почему Popen.communicate () возвращает b'hi \ n 'вместо' hi '?


92

Может ли кто-нибудь объяснить, почему результат, который я хочу, «привет», начинается с буквы «b», а после нее ставится новая строка?

Я использую Python 3.3

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

Этот дополнительный 'b' не появляется, если я запускаю его с помощью python 2.7


1
Какую версию Python вы используете?
Necrolyte2

2
Не уверен насчет 'b', но новая строка потому, что echo hiпечатает hi\r\n. Чтобы этого избежать, вы можете добавить .strip () в конце или подобное исправление.
azhrei

7
вы можете использовать check_output()вместо .communicate()здесь:print(subprocess.check_output("echo hi", shell=True, universal_newlines=True), end="")
jfs

Ответы:


22

Команда 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


5
в скобках не нужно '\'.
jfs

94

Значок bуказывает на то, что у вас есть bytesдвоичная последовательность байтов, а не строка символов Юникода. Подпроцессы выводят байты, а не символы, вот что и communicate()возвращается.

bytesТип непосредственно не в print()состоянии, так что вы время показали 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'

1
Как заставить функцию print () печатать байтовую строку без предшествующей буквы 'b'? Или вам нужно сначала преобразовать его в строку юникода?
imagineerThat

Мне любопытно, когда os.popenвозвращает текстовые строки, есть ли способ заставить их subprocess.Popenтакже возвращать их вместо байтовых строк.
Павел Шимерда

11
Я отвечу сам, есть опция с загадочным именем, universal_newlinesкоторая заставляет Popenобъект принимать и возвращать текстовые строки.
Павел Шимерда

3
@ PavelŠimerda Хотя os.popen возвращает текстовые строки, очевидно, что они неправильно декодируются для символов, отличных от ascii, по крайней мере, в Windows. Например, запуск check_output("dir"), извлечение имени файла из вывода и последующая попытка получить к нему доступ с помощью openзавершится ошибкой, если имя файла содержит немецкие умляуты. Может быть ошибка.
kdb

57

Как упоминалось ранее, 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(), эти ненужные символы будут заменены самостоятельно.


11
universal_newlines=Trueработал как шарм. Это должен быть принятый ответ, по моему скромному мнению ...
Итан Страйдер

3
Создает лишние пустые строки.
LoMaPh

1
Вам могут понадобиться как universal_newlines=True in Popen(чтобы избавиться от b''), так и a strip()в результирующей строке, если вы хотите обрезать завершающуюся новую строку.
arielf

FYI, в документации говорится, universal_newlinesчто теперь это просто обратно совместимый псевдоним для textпараметра, который более понятен, но только в Python 3.7 и выше.
Гарри Каттс

Он создает лишние пустые строки, потому что не работает. universal_newlines не удаляет \ n
kol23

8

b - это байтовое представление, а \ n - результат вывода эха.

Далее будут напечатаны только данные результата

import subprocess
print(subprocess.Popen("echo hi", shell=True,stdout=subprocess.PIPE).communicate()[0].decode('utf-8').strip())
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.