2011-12-01 10 views
5

Sto provando a eseguire il shell su un sottoprocesso non python e gli permetto di ereditare lo stdin e lo stdout da python. - Sto usando subprocess.PopenPython - subprocesses e la shell python

Questo probabilmente funziona se sto chiamando da una console, ma sicuramente non funziona quando sto usando la shell Python

(sto usando IDLE tra l'altro)

C'è un modo per convincere python a consentire a un sottoprocesso non python di stampare lo stdout nella shell python?

risposta

6

Questo funziona sia da uno script e per l'interprete interattivo, ma non da IDLE:

subprocess.Popen(whatever, stdin=sys.stdout, stdout=sys.stdin) 

Non è possibile utilizzare gli oggetti che IDLE assegna alla sys.stdin e sys.stdout come argomenti a subprocess.Popen. Questi oggetti (le interfacce della finestra shell IDLE) sono simili ai file, ma non sono veri handle di file con gli attributi fileno ei sistemi operativi Unix-like richiedono un fileno da specificare come stdin o stdout per un sottoprocesso. Non posso parlare per Windows, ma immagino che abbia requisiti simili.

+0

Su Windows IDLE viene eseguito tramite pythonw.exe, quindi non ha nemmeno gli handle di 'stdin',' stdout' e 'stderr'. – eryksun

+0

ma è un modo per ingannare Python nel farlo? – dmjalund

4

La risposta di Taymon risponde direttamente alla domanda in quanto stdin/stdout di IDLE sono in realtà oggetti simili a file e non i flussi di file standard associati a una console/terminale. Inoltre, in Windows IDLE viene eseguito con pythonw.exe, che non dispone nemmeno di una console win32 collegata.

Detto questo, se hai solo bisogno dell'output da un programma da stampare all'utente in tempo reale, in molti casi (ma non in tutti) puoi leggere l'output riga per riga e farlo eco di conseguenza. Il seguente funziona per me in Windows IDLE. Dimostra la lettura da una tubazione stdout riga per riga. Mostra anche cosa succede se il processo bufferizza la pipe, nel qual caso readline bloccherà fino a quando il buffer non è pieno o la pipe si chiude. Questo buffering può essere disabilitato manualmente con alcuni programmi (come l'opzione -u dell'interprete Python), e ci sono soluzioni alternative per Unix come stdbuf.

test1.py

import sys 
import subprocess 

def test(cmd): 
    p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE, 
         stderr=subprocess.PIPE) 
    it = iter(p.stdout.readline, b'') 
    for line in it: 
     print(line.rstrip().decode('ascii')) 

print('Testing buffered subprocess...') 
test([sys.executable, 'test2.py']) 

print('\nTesting unbuffered subprocess...') 
#-u: unbuffered binary stdout and stderr 
test([sys.executable, '-u', 'test2.py']) 

test2.py:

import time 

for i in range(5): 
    print(i) 
    time.sleep(1) 

L'uscita in IDLE dovrebbe essere seguito, con la prima serie di cifre stampate tutte in una volta dopo un ritardo e la seconda imposta riga per riga

Testing buffered subprocess... 
0 
1 
2 
3 
4 

Testing unbuffered subprocess... 
0 
1 
2 
3 
4