2013-05-08 15 views
5

ho le seguenti tre script python:La differenza tra i tubi bash e Python

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") 

Se chiamo genitore1.py con:

python3 parent1.py 

Mi dà come previsto il seguente output:

This text was created with child.py 

se chiamo parent2.py con:

python3 child.py | python3 parent2.py 

io ottenere lo stesso risultato. Ma nel primo esempio ottengo l'output di child.py come byte e nel secondo lo prendo direttamente come una stringa. Perchè è questo? E 'solo una differenza tra Python e bash pipe o c'è qualcosa che potrei fare diversamente per evitare questo?

+0

[provare questo] (http://stackoverflow.com/questions/3999114/linux-pipe-into-python-ncurses-script- stdin-and-termios? answertab = voti # tab-top) – scott

risposta

3

Quando python apre stdin e stdout, rileva quale codifica utilizzare e utilizza text I/O per fornire stringhe unicode.

Ma subprocess non rileva (e non può) la codifica del sottoprocesso avviato, quindi restituirà i byte. È possibile utilizzare un io.TextIOWrapper() instance per avvolgere il tubo child.stdout di fornire i dati unicode:

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

Sì. Mi piacerebbe aggiungere che c'è solo un tipo di pipe nel sistema operativo e che è usato da bash e Python lo stesso. L'interpretazione di un flusso può essere diversa e Python distingue i due casi; in uno interpreta l'input come byte, nell'altro come stringa/unicode. – Alfe

+0

Grazie a quello ha funzionato. Se ora voglio fare qualcosa come 'cat/bin/bash | parent2.py 'genera un errore UnicodeDecodeError perché sys.stdin.read() non restituisce byte. C'è un modo per aggirare questo? – Kritzefitz

+1

@Alfe: Beh, continua a _interprete_ l'input come byte in entrambi i casi, ma avvolge automaticamente il flusso in un 'TextIOWrapper' per te in quest'ultimo caso. È possibile ottenere il flusso di byte sottostante o collegare manualmente il proprio wrapper, in entrambi i casi. Ma ancora, un punto utile. – abarnert