2016-07-26 15 views
0

Ich möchte einen Python-Interpreter steuern, indem ich Befehle nacheinander über eine Pipe an e. G. Lassen Sie den Python-Interpreter "Hallo" drucken, warten Sie 3 Sekunden und lassen Sie dann den Python-Interpreter "Welt" drucken.Piping-Befehle in einen Python-Interpreter

Warum funktioniert der folgende Code in einer Bash:

{ echo 'from sys import stdout' ; echo 'stdout.write("hello\n")' ; echo 'stdout.flush()' ; sleep 3 ; echo 'stdout.write("world\n")' ; echo 'stdout.flush()' ; } | python3.5 -u 

zuerst wartet 3 Sekunden und dann druckt:

hello 
world 

während den folgenden Code:

{ echo 'from sys import stdout' ; echo 'stdout.write("hello\n")' ; echo 'stdout.flush()' ; sleep 3 ; echo 'stdout.write("world\n")' ; echo 'stdout.flush()' ; } | while read -r l ; do echo $l ; done 

Erstdrucke:

from sys import stdout 
stdout.write("hello\n") 
stdout.flush() 

wartet dann 3 Sekunden und schließlich druckt:

stdout.write("world\n") 
stdout.flush() 

?

Am Ende möchte ich einen zweiten Python-Interpreter von einem ersten Python-Skript wie im obigen Beispiel steuern (print "Hallo", warte 3 Sekunden, drucke "Welt"). Ist das mit dem Python-Modul "Subprozess" möglich?

Der folgende Code:

import logging 
from select import select 
from subprocess import Popen, PIPE, TimeoutExpired 
from time import sleep 
from threading import Thread 

logging.basicConfig(
    level=logging.DEBUG, 
    format="%(asctime)s %(message)s") 
logger = logging.getLogger() 

def read_stdout(proc): 
    stdout_closed, stderr_closed = False, False 

    while True: 
     rlist, wlist, xlist = select([proc.stdout, proc.stderr], [], [], 1.2) 
     if len(rlist) == 0: 
      logger.debug("timeout") 
      continue 
     if proc.stdout in rlist: 
      new_data = proc.stdout.read(1024) 
      logger.debug("new_data on stdout: %r" % new_data) 
      if len(new_data) == 0: 
       stdout_closed = True 
     if proc.stderr in rlist: 
      new_data = proc.stderr.read(1024) 
      logger.debug("new_data on stderr: %r" % new_data) 
      if len(new_data) == 0: 
       stderr_closed = True 
     if stdout_closed and stderr_closed: 
      break 

logger.debug("start") 
proc = Popen(
    #["bash", "-c", 'while read -r l ; do echo $l ; done'], 
    ["python", "-u"], 
    stdin=PIPE, 
    stdout=PIPE, 
    stderr=PIPE, 
    bufsize=0) 
thread = Thread(target=read_stdout, args=(proc,)) 
thread.start() 
proc.stdin.write(b'from sys import stdout\n') 
proc.stdin.write(b'stdout.write("hello\\n")\n') 
proc.stdin.write(b'stdout.flush()\n') 
proc.stdin.flush() 
sleep(3) 
proc.stdin.write(b'stdout.write("world\\n")\n') 
proc.stdin.write(b'stdout.flush()\n') 
proc.stdin.flush() 
proc.stdin.close() 
thread.join() 

Ergebnisse in dem gleichen Problem wie der Bash-Code oben:

Wenn Popen() ruft "Python -u", dann wird die Protokollausgabe ist:

2016-07-27 00:46:05,208 start 
2016-07-27 00:46:06,411 timeout 
2016-07-27 00:46:07,612 timeout 
2016-07-27 00:46:08,213 new_data on stdout: b'hello\nworld\n' 
2016-07-27 00:46:08,216 new_data on stdout: b'' 
2016-07-27 00:46:08,216 new_data on stderr: b'' 

während bei Popen() ruft "bash -c 'während gelesen -rl; do echo $ l; done'", dann wird die Protokollausgabe ist:

2016-07-27 00:48:37,237 start 
2016-07-27 00:48:37,239 new_data on stdout: b'from sys import stdout\n' 
2016-07-27 00:48:37,239 new_data on stdout: b'stdout.write("hello\\n")\nstdout.flush()\n' 
2016-07-27 00:48:38,440 timeout 
2016-07-27 00:48:39,642 timeout 
2016-07-27 00:48:40,242 new_data on stdout: b'stdout.write("world\\n")\n' 
2016-07-27 00:48:40,242 new_data on stdout: b'stdout.flush()\n' 
2016-07-27 00:48:40,242 new_data on stderr: b'' 
2016-07-27 00:48:40,242 new_data on stdout: b'' 
2016-07-27 00:48:40,242 new_data on stderr: b'' 

Was ist der Grund dafür, dass der Python-Interpreter den Befehl, der an ihn gesendet wird, nicht sofort ausführt? Kann das irgendwie mit dem Modul "Subprozess" erreicht werden? (Ich gehe davon aus „pexpect“, um das Problem zu lösen, aber ich mag verstehen, wenn oder warum nicht „Subprozess“ es lösen kann.)

Antwort

0

Ich habe die folgende Erklärung für das beobachtete Verhalten in „Mann python3“ gefunden:

Im nicht interaktiven Modus wird die gesamte Eingabe analysiert, bevor sie ausgeführt wird.