Почему 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.