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.