Jak używać polecenia `subprocess` z potokami


Odpowiedzi:


439

Aby użyć rury z subprocessmodułem, musisz przejść shell=True.

Nie jest to jednak zalecane z różnych powodów, między innymi z uwagi na bezpieczeństwo. Zamiast utworzyć psi grepprocesami oddzielnie, wyjście z rury jedna w drugą, tak jak poniżej:

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

Jednak w twoim konkretnym przypadku prostym rozwiązaniem jest wywołanie, subprocess.check_output(('ps', '-A'))a następnie str.findwyjście.


81
+1 za oddzielenie wyjścia / wejścia, aby uniknąć użyciashell=True
Nicolas

5
Nie zapominaj, błąd subprocess.CalledProcessError: Command '('grep', 'process_name')' returned non-zero exit status 1oznacza po prostu, że grep nic nie znalazł, więc jest to normalne zachowanie.
Serge

2
Dlaczego potrzebujemy, ps.wait()kiedy mamy już dane wyjściowe. ps.wait.__doc__czeka na zakończenie przez dziecko, ale zawartość dziecka wydaje się już umieszczona w outputzmiennej
Papouche Guinslyzinho,

3
@MakisH Patrzysz string.find, co zostało przestarzałe na korzyść str.find(tj. Metody findna strobiektach).
Taymon

4
Uwaga: jeśli grepumrze przedwcześnie; psmoże zawiesić się na czas nieokreślony, jeśli wygeneruje wystarczającą moc wyjściową do wypełnienia bufora potoku systemu operacyjnego (ponieważ nie wywołano ps.stdout.close()elementu nadrzędnego). Zamień kolejność początkową, aby tego uniknąć
jfs

54

Lub zawsze możesz użyć metody komunikacji na obiektach podprocesu.

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

Metoda komunikacji zwraca krotkę standardowego wyjścia i standardowy błąd.


3
Myślę, że używanie communicatejest lepsze niż wait. Występuje takie ostrzeżenie: „Spowoduje to zakleszczenie przy użyciu stdout = PIPE i / lub stderr = PIPE, a proces potomny generuje wystarczającą moc wyjściową do potoku, tak że blokuje on oczekiwanie na bufor potoku systemu operacyjnego, aby zaakceptować więcej danych. unikaj tego ”.
Paolo,

2
Aby wyjaśnić powyższy komentarz Paolo, ostrzeżenie dotyczy oczekiwania, a nie komunikowania się - to jest powód, dla którego mówi, że komunikacja jest lepsza.
EnemyBagJones,

23

Zobacz dokumentację dotyczącą konfigurowania potoku za pomocą podprocesu: http://docs.python.org/2/library/subprocess.html#replacing-shell-pipeline

Nie testowałem następującego przykładu kodu, ale powinien on być mniej więcej taki, jak chcesz:

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
Po sprawdzeniu tego nie powiodła się, patrz odpowiedź poniżej Taymon za coś, co działa bez mucking
Alvin

2
Subprocess.check_output nie wydaje się istnieć w Pythonie 2.6.9
RightmireM

6

Rozwiązanie JKALAVIS jest dobre, ale dodałbym ulepszenie do używania shlex zamiast SHELL = TRUE. poniżej przedstawiam czasy zapytania

#!/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
Dlaczego Shellx over Shell?
AFP_555,

2
gdzie jest używany shlex?
3lokh

4

Spróbuj także użyć 'pgrep'polecenia zamiast'ps -A | grep 'process_name'


2
jeśli chcesz uzyskać identyfikator procesu, oczywiście
Shooe,

3

Możesz wypróbować funkcjonalność potoku w sh.py :

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

-1

Po Python 3.5 możesz także używać:

    import subprocess

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

Wykonanie polecenia blokuje, a dane wyjściowe będą przetwarzane . Proces .

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.