Popen.communicate () neden 'hi' yerine b'hi \ n 'döndürüyor?


92

Birisi neden istediğim sonucun, "merhaba" nın önünde bir 'b' harfi ve ardından yeni bir satır olduğunu açıklayabilir mi?

Python 3.3 kullanıyorum

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

Python 2.7 ile çalıştırırsam bu fazladan 'b' görünmüyor


1
Python'un hangi sürümünü kullanıyorsunuz?
Necrolyte2

2
'B' konusunda emin değilim, ancak satırsonu echo hiyazdırdığı için hi\r\n. Bunu önlemek için, sonuna .strip () veya benzer bir düzeltme ekleyebilirsiniz.
azhrei

7
buranın check_output()yerine kullanabilirsiniz .communicate():print(subprocess.check_output("echo hi", shell=True, universal_newlines=True), end="")
jfs

Yanıtlar:


22

Echo komutu varsayılan olarak bir yeni satır karakteri döndürür

Bununla karşılaştırın:

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

Dizeden önceki b'ye gelince , Python 2.6+ 'da normal bir dizgeye eşdeğer bir bayt dizisi olduğunu gösterir.

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


5
parantez içinde "\" ifadesine ihtiyacınız yoktur.
jfs

94

bNe var olduğunu gösterir bytesbayt ikili dizisi ziyade Unicode karakter dizesidir olan. Alt süreçler karakterleri değil, baytları çıktılar, yani communicate()geri dönen şey budur.

bytesTipi doğrudan değil print()size gösterilen ediliyoruz yüzden, mümkün reprait bytessahip. Alt işlemden aldığınız baytların kodlamasını biliyorsanız, decode()bunları yazdırılabilir hale dönüştürmek için kullanabilirsiniz str:

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

Elbette, bu belirli örnek yalnızca alt işlemden gerçekten ASCII alıyorsanız işe yarar. ASCII değilse, bir istisna alırsınız:

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

Satırsonu, echo hiçıktıya sahip olanın bir parçasıdır . echo'nin görevi, geçirdiğiniz parametreleri, ardından bir satırsonu ile çıktılamaktır. İşlem çıktısını çevreleyen boşluklarla ilgilenmiyorsanız, şu şekilde kullanabilirsiniz strip():

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

1
Print () işlevinin bir bayt dizesini önünde 'b' olmadan yazdırmasını nasıl sağlarsınız? Yoksa önce onu bir unicode dizesine dönüştürmeniz mi gerekiyor?
imagineerThat

os.popenMetin dizelerini döndürdüğünde subprocess.Popen, bayt dizeleri yerine onları döndürmenin bir yolu olup olmadığını merak ediyorum .
Pavel Šimerda

11
Kendim cevaplayacağım universal_newlines, Popennesnenin metin dizelerini kabul etmesine ve döndürmesine neden olan şifreli adı olan bir seçenek var .
Pavel Šimerda

3
@ PavelŠimerda os.popen metin dizeleri döndürürken, görünüşe göre ascii olmayan karakterler için, en azından Windows'ta, yanlış kod çözülüyor. Örneğin check_output("dir"), çıktıdan bir dosya adını çalıştırmak , çıkarmak ve sonra ona erişmeye çalışmak open, dosya adı Almanca umlaut içeriyorsa başarısız olacaktır. Bir hata olabilir.
kdb

57

Daha önce de belirtildiği gibi, echo hiaslında geri döner hi\n, bu beklenen bir davranıştır.

Ama muhtemelen veriyi "doğru" biçimde almak ve kodlama ile uğraşmak istemezsiniz. Yapmanız gereken tek şey, universal_newlines=Truebunu subprocess.Popen()beğenmek için seçeneği geçmek :

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

Bu şekilde Popen(), bu istenmeyen semboller kendi kendine değiştirilecektir.


11
universal_newlines=Truebir cazibe gibi çalıştı. Alçakgönüllü görüşüme göre kabul edilen cevap bu olmalı ...
Ethan Strider

3
Ekstra boş satırlar üretir.
LoMaPh

1
Sonlanan satırsonu satırını kesmek istiyorsanız, sonuç dizgesinde hem universal_newlines=True in Popen(ondan kurtulmak için b'') hem de a'ya ihtiyacınız olabilir strip().
arielf

Bilginize, dokümantasyonuniversal_newlines artık textparametre için geriye dönük uyumlu bir takma ad olduğunu söylüyor , bu daha net ancak yalnızca Python 3.7 ve üzerinde.
Harry Cutts

Çalışmadığı için fazladan boş satırlar üretir. universal_newlines kaldırmıyor \ n
kol23

8

b, bayt gösterimidir ve \ n, yankı çıktısının sonucudur.

Aşağıdakiler sadece sonuç verilerini yazdıracaktır

import subprocess
print(subprocess.Popen("echo hi", shell=True,stdout=subprocess.PIPE).communicate()[0].decode('utf-8').strip())
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.