Dlaczego Popen.communicate () zwraca b'hi \ n 'zamiast' hi '?


92

Czy ktoś może wyjaśnić, dlaczego oczekiwany przeze mnie wynik, „cześć”, jest poprzedzony literą „b” i zakończony nową linią?

Używam Pythona 3.3

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

To dodatkowe `` b '' nie pojawia się, jeśli uruchomię go z Pythonem 2.7


1
Jakiej wersji Pythona używasz?
Necrolyte2

2
Nie jestem pewien co do „b”, ale znak nowej linii jest taki, że jest echo hidrukowany hi\r\n. Aby tego uniknąć, możesz dodać .strip () na końcu lub podobną poprawkę.
azhrei

7
możesz użyć check_output()zamiast .communicate()tutaj:print(subprocess.check_output("echo hi", shell=True, universal_newlines=True), end="")
jfs

Odpowiedzi:



94

Symbol bwskazuje, że to, co masz bytes, jest binarną sekwencją bajtów, a nie ciągiem znaków Unicode. Podprocesy wysyłają bajty, a nie znaki, więc to właśnie communicate()zwraca.

bytesTyp nie jest bezpośrednio print()w stanie, więc jesteś jest pokazany reprz bytesmasz. Jeśli znasz kodowanie bajtów, które otrzymałeś z podprocesu, możesz użyć ich decode()do przekształcenia ich w plik drukowalny str:

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

Oczywiście ten konkretny przykład działa tylko wtedy, gdy faktycznie otrzymujesz ASCII z podprocesu. Jeśli to nie jest ASCII, pojawi się wyjątek:

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

Nowa linia jest częścią echo hiwyniku. echoZadanie polega na wyświetleniu przekazanych parametrów, po których następuje znak nowej linii. Jeśli nie jesteś zainteresowany białymi znakami otaczającymi wyjście procesu, możesz użyć w ten strip()sposób:

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

1
Jak sprawić, by funkcja print () wyświetlała ciąg bajtów bez poprzedzającego go „b”? A może musisz najpierw przekonwertować go na ciąg znaków Unicode?
imagineerThat

Jestem ciekawy, kiedy os.popenzwraca ciągi tekstowe, czy istnieje sposób, aby subprocess.Popenrównież je zwrócić, zamiast ciągów bajtów.
Pavel Šimerda

11
Odpowiem sobie, istnieje opcja z tajemniczą nazwą, universal_newlinesktóra powoduje, że Popenobiekt przyjmuje i zwraca ciągi tekstowe.
Pavel Šimerda

3
@ PavelŠimerda Podczas gdy os.popen zwraca ciągi tekstowe, najwyraźniej są one nieprawidłowo dekodowane dla znaków innych niż ASCII, przynajmniej w systemie Windows. Np. Uruchomienie check_output("dir"), wyodrębnienie nazwy pliku z wyjścia, a następnie próba uzyskania do niego dostępu nie openpowiedzie się, jeśli nazwa pliku zawiera niemieckie umlauty. To może być błąd.
kdb

57

Jak wspomniano wcześniej, echo hifaktycznie wracahi\n , co jest oczekiwanym zachowaniem.

Ale prawdopodobnie chcesz po prostu uzyskać dane w „odpowiednim” formacie i nie zajmować się kodowaniem. Wystarczy, że przekażesz universal_newlines=Trueopcję subprocess.Popen()polubienia:

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

W ten sposób sam Popen()zastąpi te niechciane symbole.


11
universal_newlines=Truedziałał jak urok. To powinna być akceptowana odpowiedź, moim skromnym zdaniem ...
Ethan Strider,

3
Tworzy dodatkowe puste linie.
LoMaPh

1
Jeśli chcesz odciąć kończący znak nowej linii, możesz potrzebować zarówno universal_newlines=True in Popen(aby pozbyć się b''), jak i a strip()na otrzymanym ciągu.
arielf

FYI, dokumentacja mówi, że universal_newlinesjest teraz tylko zgodnym wstecz aliasem textparametru, który jest bardziej przejrzysty, ale tylko w Pythonie 3.7 i nowszych.
Harry Cutts

Tworzy dodatkowe puste wiersze, ponieważ nie działa. universal_newlines nie usuwa \ n
kol23

8

b jest reprezentacją bajtową, a \ n jest wynikiem wyjścia echa.

Następujące spowoduje wydrukowanie tylko danych wyników

import subprocess
print(subprocess.Popen("echo hi", shell=True,stdout=subprocess.PIPE).communicate()[0].decode('utf-8').strip())
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.