Verwendung des Befehls "subprocess" mit Pipes

Antworten:

438

Um ein Rohr mit dem subprocessModul zu verwenden, müssen Sie passieren shell=True.

Dies ist jedoch aus verschiedenen Gründen nicht wirklich ratsam, nicht zuletzt aus Sicherheitsgründen. Erstellen Sie stattdessen die psund grep-Prozesse separat und leiten Sie die Ausgabe wie folgt von einer zur anderen weiter:

ps = subprocess.Popen(('ps', '-A'), stdout=subprocess.PIPE)
output = subprocess.check_output(('grep', 'process_name'), stdin=ps.stdout)
ps.wait()

In Ihrem speziellen Fall besteht die einfache Lösung jedoch darin, die Ausgabe aufzurufen subprocess.check_output(('ps', '-A'))und dann str.findzu aktivieren.

Taymon
quelle
81
+1 für die Trennung der Ausgabe / Eingabe, um die Verwendung zu vermeidenshell=True
Nicolas
5
Vergiss nicht, Fehler subprocess.CalledProcessError: Command '('grep', 'process_name')' returned non-zero exit status 1bedeutet nur, dass grep nichts gefunden hat, also ist es normales Verhalten.
Serge
2
Warum brauchen wir das ps.wait()für, wenn wir bereits die Ausgabe haben. ps.wait.__doc__wartet auf die Beendigung des Kindes, aber der Inhalt des Kindes scheint bereits in der outputVariablen platziert zu sein
Papouche Guinslyzinho
3
@MakisH Sie sehen string.find, was zugunsten von str.find(dh der Methode findfür strObjekte) veraltet ist .
Taymon
4
Hinweis: wenn grepvorzeitig stirbt; pskann auf unbestimmte Zeit hängen bleiben, wenn es genügend Ausgabe erzeugt, um seinen OS-Pipe-Puffer zu füllen (weil Sie ps.stdout.close()das übergeordnete Element nicht aufgerufen haben ). Tauschen Sie die Startreihenfolge aus, um dies zu vermeiden
jfs
54

Oder Sie können die Kommunikationsmethode immer für die Unterprozessobjekte verwenden.

cmd = "ps -A|grep 'process_name'"
ps = subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE,stderr=subprocess.STDOUT)
output = ps.communicate()[0]
print(output)

Die Kommunikationsmethode gibt ein Tupel der Standardausgabe und des Standardfehlers zurück.

jkalivas
quelle
3
Ich denke mit communicateist besser als wait. Es gibt eine solche Warnung: "Dies führt zu einem Deadlock bei Verwendung von stdout = PIPE und / oder stderr = PIPE, und der untergeordnete Prozess generiert genügend Ausgabe für eine Pipe, sodass das Warten auf den OS-Pipe-Puffer blockiert wird, um weitere Daten zu akzeptieren. Verwenden Sie communic () to vermeide das. "
Paolo
2
Um Paolos obigen Kommentar zu verdeutlichen, ist die Warnung das Warten, nicht das Kommunizieren - dh der Grund, warum er sagt, dass Kommunikation besser ist.
EnemyBagJones
23

Weitere Informationen zum Einrichten einer Pipeline mithilfe eines Unterprozesses finden Sie in der Dokumentation: http://docs.python.org/2/library/subprocess.html#replacing-shell-pipeline

Ich habe das folgende Codebeispiel nicht getestet, aber es sollte ungefähr das sein, was Sie wollen:

query = "process_name"
ps_process = Popen(["ps", "-A"], stdout=PIPE)
grep_process = Popen(["grep", query], stdin=ps_process.stdout, stdout=PIPE)
ps_process.stdout.close()  # Allow ps_process to receive a SIGPIPE if grep_process exits.
output = grep_process.communicate()[0]
AlcubierreDrive
quelle
2
Wenn Sie überprüfen, ob dies fehlgeschlagen ist, lesen Sie die Antwort von Taymon für etwas, das funktioniert, ohne herumzuspielen
Alvin
2
subprocess.check_output scheint in Python 2.6.9
RightmireM
6

Die JKALAVIS-Lösung ist gut, ich würde jedoch eine Verbesserung hinzufügen, um Shlex anstelle von SHELL = TRUE zu verwenden. unten grep ich die Abfragezeiten aus

#!/bin/python
import subprocess
import shlex

cmd = "dig @8.8.4.4 +notcp www.google.com|grep 'Query'"
ps = subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE,stderr=subprocess.STDOUT)
output = ps.communicate()[0]
print(output)
Daniel Smith
quelle
1
Warum Shellx über Shell?
AFP_555
2
Wo wird Shlex hier verwendet?
3lokh
4

Versuchen Sie auch, den 'pgrep'Befehl anstelle von zu verwenden'ps -A | grep 'process_name'

Shooe
quelle
2
Wenn Sie Prozess-ID erhalten möchten, natürlich
Shooe
3

Sie können die Pipe-Funktionalität in sh.py ausprobieren :

import sh
print sh.grep(sh.ps("-ax"), "process_name")
amoffat
quelle
0

Nach Python 3.5 können Sie auch Folgendes verwenden:

    import subprocess

    f = open('test.txt', 'w')
    process = subprocess.run(['ls', '-la'], stdout=subprocess.PIPE, universal_newlines=True)
    f.write(process.stdout)
    f.close()

Die Ausführung des Befehls blockiert und die Ausgabe erfolgt in process.stdout .

Zingi
quelle