2012-03-26 5 views
4

Innerhalb eines subprocess Anruf hängen, möchte ich Shell verwenden = True, so dass es auf Pfadnamen (Code unten) ist Globbing jedoch this has the annoying side-effect of making subprocess spawn a child process (die dann sein muss, `communicate() d/poll() ed/wait() ed/beende() d/kill() ed/whatevah).Correct Beschwörung von subprocess mit Shell = True Ausgabe zu erhalten und nicht

(Ja, ich bin der Globbing bewusst auch mit fnmatch/glob getan werden kann, aber zeigen Sie mir bitte die ‚richtige‘ Verwendung von subprocess auf diesem, dh die minimale Beschwörung, um sowohl die stdout bekommen und das Kind Prozess zu stoppen.)

Dieses funktioniert gut (liefert Ausgabe):

subprocess.check_output(['/usr/bin/wc','-l','[A-Z]*/[A-Z]*.F*'], shell=False)

aber dies hängt

subprocess.check_output(['/usr/bin/wc','-l','[A-Z]*/[A-Z]*.F*'], shell=True)

(PS: Es ist erschwerenden ernst, dass man nicht sagen kann, subprocess Sie einige aber nicht alle Shell Funktionalität z.B. globbing, aber nicht laichen. Ich denke, es ist ein würdiger PEP, dass, wenn jemand einen Kommentar kümmert, übergeben, dh in einem Tupel von Booleschen oder ein oder von Binärflags)

(PPS: das Idiom, ob Sie subprocess...(cmdstring.split() or [...]) Pass ist nur Ein trivialer idiomatischer Unterschied. Ich sage tomate, du sagst tomay-to. In meinem Fall ist die Motivation, dass der Befehl behoben ist, aber ich möchte es mehr als einmal mit einer anderen Dateispezifikation aufrufen.)

+1

Wie würden Sie dem zugrunde liegenden _shell_ sagen, dass Sie nur einige, aber nicht alle Funktionen haben wollen?Bis die zugrunde liegende Shell dies unterstützt (über ein weites Array von Plattformen), gibt es nicht viel Unterstützung für eine API, um darauf zuzugreifen ... –

+0

@Charles: Ich habe nicht gesagt Shell sagen. Ich sagte ***, Unterprozess *** zu erzählen. Subprozess kann mit Calls zu fnmatch anstelle von ausgewachsener Shell vortäuschen, ich gebe wirklich keinen Laut von sich, wie er es erreicht. Aber das ist machbar, wenn es schmerzhaft ist. – smci

+0

Ich habe 'shell = True' gelesen, um zu sagen, dass ich eine tatsächliche UNIX-Shell aufrufen möchte. Wenn Sie plötzlich 'subprocess' * faking * als eine Shell haben, fragen Sie sie, um herauszufinden, was das Richtige (oder zumindest die erwartete Sache) auf der nativen Shell jeder Plattform ist, die Python unterstützt. Denken Sie daran, dass verschiedene Shells unterschiedliche Varianten der Glob-Syntax, verschiedene Formen der Umleitung, verschiedene Flusskontrollkonstrukte (wie sie sicher in One-Linern verwendet werden können, die durch "Subprozess" gestartet werden) unterstützen ... Sie müssten im Grunde ein implementieren tatsächliche UNIX-Shell in Python, und das wäre verrückt. –

Antwort

6

Es gibt sehr wenig Punkt, um ein Array zu übergeben:

subprocess.check_output(['/usr/bin/wc','-l','A-Z*/A-Z*.F*'], shell=True) 

... als dies läuft einfach wc ohne Argumente, in einer Shell übergeben auch die Argumente -l und A-Z*/A-Z*.F* als Argumente (an die Shell, nicht an wc). Stattdessen möchten Sie:

subprocess.check_output('/usr/bin/wc -l A-Z*/A-Z*.F*', shell=True) 

Bevor korrigiert wird, würde dies hängen, weil wc keine Argumente hatte und wurde von stdin zu lesen. Ich würde vorschlagen, sicherzustellen, dass stdin geschlossen übergeben wird, anstatt die stdin Ihres Python-Programms übergeben (wie das Standardverhalten ist).

Eine einfache Möglichkeit, dies zu tun, da Sie shell=True haben:

subprocess.check_output(
    '/usr/bin/wc -l A-Z*/A-Z*.F* </dev/null', 
    shell=True) 

... abwechselnd:

p = subprocess.Popen('/usr/bin/wc -l A-Z*/A-Z*.F*', shell=True, 
        stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=None) 
(output, _) = p.communicate(input='') 

... die eher eine leere stdin aus Python-Code sicherzustellen, als Berufung auf der Schale.

+0

Aha! Richtig, die Dateien existieren in einigen, aber nicht in allen globbed-Unterverzeichnissen. Ich nehme an, dass Subprozesse keine wahnwitzigen Dinge wie Spawnen ohne Argumente sind. Wie mache ich das ohne extreme Schmerzen? (und andere als manuelle Verwendung von fnmatch)? Ich meine, das UNIX-Äquivalent *** funktioniert einfach ***. – smci

+0

@smci nein, das UNIX-Äquivalent funktioniert nicht einfach - es hat genau das gleiche Problem, zumindest wenn die 'nullglob'-Shell-Option wahr ist (was aus genau diesem Grund zugegebenermaßen nicht standardmäßig ist) . Siehe auch meinen Änderungsantrag. –

+0

Interessant. Es hängt immer noch mit umgeleiteten '* smci