2013-05-08 19 views
5

I mają następujące trzy scenariusze: pytonaRóżnica między rurami basha pytona

parent1.py

import subprocess, os, sys 

relpath = os.path.dirname(sys.argv[0]) 
path = os.path.abspath(relpath) 
child = subprocess.Popen([os.path.join(path, 'child.lisp')], stdout = subprocess.PIPE) 
sys.stdin = child.stdout 
inp = sys.stdin.read() 
print(inp.decode()) 

parent2.py:

import sys 
inp = sys.stdin 
print(inp) 

child.py:

print("This text was created in child.py") 

Jeśli zadzwonię do parent1.py z:

python3 parent1.py 

daje mi jak oczekiwany następujący wynik:

This text was created with child.py 

jeśli zgłoszę parent2.py z:

python3 child.py | python3 parent2.py 

uzyskać ten sam wynik. Ale w pierwszym przykładzie otrzymuję dane wyjściowe pliku child.py jako bajty, a w drugim otrzymuję je bezpośrednio jako ciąg znaków. Dlaczego to? Czy jest to tylko różnica między python i bash pipe lub czy jest coś, co mógłbym zrobić inaczej, aby tego uniknąć?

+0

[Try This] (http://stackoverflow.com/questions/3999114/linux-pipe-into-python-ncurses-script- stdin-and-termios? answerertab = głosów # tab-top) – scott

Odpowiedz

3

Gdy pyton otwiera się stdin i stdout, wykrywa kodowanie, którego należy użyć i używa text I/O, aby podać ciągi znaków Unicode.

Ale subprocess nie (i nie może) wykryć kodowania podprocesu, który uruchomiłeś, więc zwróci bajty. Można użyć io.TextIOWrapper() instance owinąć rurę child.stdout dostarczenie danych Unicode:

sys.stdin = io.TextIOWrapper(child.stdout, encoding='utf8') 
+2

Tak. Chciałbym dodać, że w systemie operacyjnym istnieje tylko jeden rodzaj potoków, który jest używany przez bash i Python. Interpretacja strumienia może być różna, a Python rozróżnia dwa przypadki; w jednym interpretuje dane wejściowe jako bajty, w drugim jako ciąg/unicode. – Alfe

+0

Dzięki, że zadziałało. Jeśli chcę teraz zrobić coś w stylu "cat/bin/bash | parent2.py "podnosi UnicodeDecodeError, ponieważ sys.stdin.read() nie zwraca bajtów. Czy istnieje sposób obejścia tego? – Kritzefitz

+1

@Alfe: Cóż, to nadal _interpretuje wejście jako bajty w obu przypadkach, po prostu automatycznie opakowuje strumień w 'TextIOWrapper' dla ciebie w tym drugim przypadku. Możesz uzyskać dostęp do podstawowego strumienia bajtów lub ręcznie dołączyć własne opakowanie, w obu przypadkach. Ale nadal, przydatny punkt. – abarnert