Verwendung des Befehls "subprocess" mit Pipes


246

Ich möchte verwenden subprocess.check_output()mit ps -A | grep 'process_name'. Ich habe verschiedene Lösungen ausprobiert, aber bisher hat nichts funktioniert. Kann mir jemand zeigen, wie es geht?



4
Es gibt psutildie Möglichkeit, Prozessinformationen auf tragbare Weise abzurufen.
— JFS

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.


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.


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]

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)

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'


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


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 .

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.