Tại sao Popen.communicate () trả về b'hi \ n 'thay vì' hi '?


93

Ai đó có thể giải thích tại sao kết quả tôi muốn, "hi", được đặt trước bằng chữ cái 'b' và theo sau là dòng mới không?

Tôi đang sử dụng Python 3.3

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

Thêm 'b' này không xuất hiện nếu tôi chạy nó với python 2.7


1
Bạn đang sử dụng phiên bản Python nào?
Necrolyte2

2
Không chắc về chữ 'b', nhưng dòng mới là do echo hibản in hi\r\n. Để tránh điều đó, bạn có thể thêm .strip () vào cuối hoặc sửa chữa tương tự.
azhrei

7
bạn có thể sử dụng check_output()thay vì .communicate()ở đây:print(subprocess.check_output("echo hi", shell=True, universal_newlines=True), end="")
jfs

Câu trả lời:


21

Lệnh echo theo mặc định trả về một ký tự dòng mới

So sánh với cái này:

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

Đối với b đứng trước chuỗi, nó chỉ ra rằng đó là một chuỗi byte tương đương với một chuỗi bình thường trong Python 2.6+

http://docs.python.org/3/reference/lexical_analysis.html#literals


5
bạn không cần '\' bên trong dấu ngoặc đơn.
jfs

95

Dấu bchỉ ra rằng những gì bạn có là bytesmột chuỗi nhị phân của các byte chứ không phải là một chuỗi các ký tự Unicode. Các quy trình con xuất ra các byte, không phải ký tự, vì vậy đó là những gì communicate()đang trả về.

Các bytesloại là không trực tiếp print()có thể, vì vậy bạn được hiển thị trong reprcủa bytesbạn có. Nếu bạn biết mã hóa của các byte bạn nhận được từ quy trình con, bạn có thể sử dụng decode()để chuyển đổi chúng thành một tệp có thể in được str:

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

Tất nhiên, ví dụ cụ thể này chỉ hoạt động nếu bạn thực sự đang nhận ASCII từ quy trình con. Nếu nó không phải là ASCII, bạn sẽ nhận được một ngoại lệ:

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

Dòng mới là một phần của những gì echo hicó đầu ra. echoCông việc của bạn là xuất các tham số bạn truyền vào, theo sau là một dòng mới. Nếu bạn không quan tâm đến khoảng trắng xung quanh đầu ra quy trình, bạn có thể sử dụng strip()như vậy:

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

1
Làm thế nào để bạn có được hàm print () để in một chuỗi byte mà không có 'b' ở trước? Hay bạn cần chuyển nó thành chuỗi unicode trước?
ImagineerThat

Tôi tò mò, khi os.popentrả về chuỗi văn bản, liệu có cách nào để subprocess.Popentrả về chúng, thay vì chuỗi byte hay không.
Pavel Šimerda

11
Tôi sẽ tự trả lời, có một tùy chọn có tên khó hiểu universal_newlineskhiến Popenđối tượng chấp nhận và trả về chuỗi văn bản.
Pavel Šimerda

3
@ PavelŠimerda Trong khi os.popen trả về các chuỗi văn bản, chúng dường như đang được giải mã không chính xác cho các ký tự không phải ascii, ít nhất là trên Windows. Ví dụ: chạy check_output("dir"), trích xuất tên tệp từ đầu ra và sau đó cố gắng truy cập nó bằng opensẽ không thành công nếu tên tệp chứa âm sắc tiếng Đức. Có thể là một lỗi.
kdb

57

Như đã đề cập trước đây, echo hithực sự trả về hi\n, đó là một hành vi được mong đợi.

Nhưng bạn có thể muốn chỉ lấy dữ liệu ở định dạng "đúng" và không phải đối phó với mã hóa. Tất cả những gì bạn cần làm là vượt qua universal_newlines=Truetùy chọn để subprocess.Popen()thích như vậy:

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

Cách này Popen()sẽ tự thay thế các ký hiệu không mong muốn này.


11
universal_newlines=Truelàm việc như người ở. Điều này sẽ là câu trả lời được chấp nhận, theo ý kiến khiêm tốn của tôi ...
Ethan Strider

3
Nó tạo ra các dòng trống.
LoMaPh

1
Bạn có thể cần cả universal_newlines=True in Popen(để loại bỏ b'') và a strip()trên chuỗi kết quả, nếu bạn muốn cắt dòng mới kết thúc.
arielf

FYI, tài liệu cho biết universal_newlinesbây giờ chỉ là một bí danh tương thích ngược cho texttham số, rõ ràng hơn nhưng chỉ trong Python 3.7 trở lên.
Harry Cutts

Nó tạo thêm các dòng trống bởi vì nó không hoạt động. Universal_newlines không xóa \ n
kol23

8

b là biểu diễn byte và \ n là kết quả của đầu ra tiếng vọng.

Sau đây sẽ chỉ in dữ liệu kết quả

import subprocess
print(subprocess.Popen("echo hi", shell=True,stdout=subprocess.PIPE).communicate()[0].decode('utf-8').strip())
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.