Чому Popen.communicate () повертає b'hi \ n 'замість "hi"?


93

Хтось може пояснити, чому перед результатом, який я хочу, «привіт», стоїть буква «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 () наприкінці або подібне виправлення.
azrei

7
Ви можете використати check_output()замість .communicate()цього:print(subprocess.check_output("echo hi", shell=True, universal_newlines=True), end="")
jfs

Відповіді:


21

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

95

bВказує на те , що у вас є bytes, що двійкова послідовність байтів , а не рядок символів Unicode. Підпроцеси виводять байти, а не символи, тому ось що 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"? Або вам спочатку потрібно перетворити його на рядок Unicode?
уявітель, що

Мені цікаво, коли 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.