Odpowiedź na to pytanie zależy od używanej wersji języka Python. Najprostszym podejściem jest użycie subprocess.check_output
funkcji:
>>> subprocess.check_output(['ls', '-l'])
b'total 0\n-rw-r--r-- 1 memyself staff 0 Mar 14 11:04 files\n'
check_output
uruchamia pojedynczy program, który przyjmuje tylko argumenty jako dane wejściowe. 1 Zwraca wynik dokładnie tak, jak wydrukowano stdout
. Jeśli chcesz zapisać dane wejściowe stdin
, przejdź do sekcji run
lub Popen
. Jeśli chcesz wykonywać złożone polecenia powłoki, zobacz uwagę na shell=True
końcu tej odpowiedzi.
Ta check_output
funkcja działa na prawie wszystkich wersjach Pythona, które są nadal w powszechnym użyciu (2.7+). 2 Jednak w przypadku nowszych wersji nie jest to już zalecane podejście.
Nowoczesne wersje Python (3.5 lub nowszy): run
Jeśli używasz języka Python 3.5 lub nowszego i nie potrzebujesz kompatybilności wstecznej , nowa run
funkcja jest zalecana. Zapewnia bardzo ogólny interfejs API wysokiego poziomu dla subprocess
modułu. Aby przechwycić dane wyjściowe programu, przekaż subprocess.PIPE
flagę do stdout
argumentu słowa kluczowego. Następnie uzyskaj dostęp do stdout
atrybutu zwróconego CompletedProcess
obiektu:
>>> import subprocess
>>> result = subprocess.run(['ls', '-l'], stdout=subprocess.PIPE)
>>> result.stdout
b'total 0\n-rw-r--r-- 1 memyself staff 0 Mar 14 11:04 files\n'
Zwracana wartość to bytes
obiekt, więc jeśli potrzebujesz odpowiedniego ciągu, musisz decode
go. Zakładając, że wywoływany proces zwraca łańcuch zakodowany w UTF-8:
>>> result.stdout.decode('utf-8')
'total 0\n-rw-r--r-- 1 memyself staff 0 Mar 14 11:04 files\n'
Wszystko to można skompresować do jednej linijki:
>>> subprocess.run(['ls', '-l'], stdout=subprocess.PIPE).stdout.decode('utf-8')
'total 0\n-rw-r--r-- 1 memyself staff 0 Mar 14 11:04 files\n'
Jeśli chcesz przekazać dane wejściowe do procesu stdin
, przekaż bytes
obiekt do input
argumentu słowa kluczowego:
>>> cmd = ['awk', 'length($0) > 5']
>>> input = 'foo\nfoofoo\n'.encode('utf-8')
>>> result = subprocess.run(cmd, stdout=subprocess.PIPE, input=input)
>>> result.stdout.decode('utf-8')
'foofoo\n'
Błędy można wychwytywać, przekazując stderr=subprocess.PIPE
(przechwytywanie do result.stderr
) lub stderr=subprocess.STDOUT
(przechwytywanie result.stdout
wraz ze zwykłym wyjściem). Gdy bezpieczeństwo nie stanowi problemu, możesz także uruchamiać bardziej złożone polecenia powłoki, przekazując shell=True
zgodnie z opisem w uwagach poniżej.
Dodaje to nieco złożoności w porównaniu do starego sposobu robienia rzeczy. Ale myślę, że jest to opłacalne: teraz możesz zrobić prawie wszystko, co musisz zrobić z run
samą funkcją.
Starsze wersje Pythona (2.7-3.4): check_output
Jeśli używasz starszej wersji Pythona lub potrzebujesz skromnej kompatybilności wstecznej, prawdopodobnie możesz użyć tej check_output
funkcji w skrócie opisany powyżej. Jest dostępny od wersji Python 2.7.
subprocess.check_output(*popenargs, **kwargs)
Pobiera te same argumenty co Popen
(patrz poniżej) i zwraca ciąg zawierający dane wyjściowe programu. Początek tej odpowiedzi zawiera bardziej szczegółowy przykład użycia. W Pythonie 3.5 i nowszych check_output
jest równoważne wykonywaniu za run
pomocą check=True
i stdout=PIPE
i zwracaniu tylko stdout
atrybutu.
Możesz przekazać, stderr=subprocess.STDOUT
aby upewnić się, że komunikaty o błędach są uwzględnione w zwróconych danych wyjściowych - ale w niektórych wersjach przekazywanie stderr=subprocess.PIPE
do Pythona check_output
może powodować zakleszczenia . Gdy bezpieczeństwo nie stanowi problemu, możesz także uruchamiać bardziej złożone polecenia powłoki, przekazując shell=True
zgodnie z opisem w uwagach poniżej.
Jeśli potrzebujesz potokować stderr
lub przekazywać dane wejściowe do procesu, check_output
nie będzie to do zadania. Popen
W takim przypadku zobacz poniższe przykłady.
Złożone aplikacje i starsze wersje Pythona (2.6 i poniżej): Popen
Jeśli potrzebujesz głębokiej kompatybilności wstecznej lub potrzebujesz bardziej wyrafinowanej funkcjonalności niż check_output
zapewnia, będziesz musiał pracować bezpośrednio z Popen
obiektami, które zawierają niskopoziomowy interfejs API dla podprocesów.
Popen
Konstruktor przyjmuje zarówno pojedyncze polecenie , bez argumentów lub listy zawierającej polecenie jako jego pierwszej pozycji, a po dowolnej liczbie argumentów każdej jako oddzielny element na liście. shlex.split
może pomóc w analizie ciągów znaków w odpowiednio sformatowanych listach. Popen
obiekty akceptują również wiele różnych argumentów do zarządzania procesami IO i konfiguracji niskiego poziomu.
Wysyłanie danych wejściowych i przechwytywanie danych wyjściowych communicate
jest prawie zawsze preferowaną metodą. Jak w:
output = subprocess.Popen(["mycmd", "myarg"],
stdout=subprocess.PIPE).communicate()[0]
Lub
>>> import subprocess
>>> p = subprocess.Popen(['ls', '-a'], stdout=subprocess.PIPE,
... stderr=subprocess.PIPE)
>>> out, err = p.communicate()
>>> print out
.
..
foo
Jeśli ustawisz stdin=PIPE
, communicate
pozwala również na przekazywanie danych do procesu poprzez stdin
:
>>> cmd = ['awk', 'length($0) > 5']
>>> p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
... stderr=subprocess.PIPE,
... stdin=subprocess.PIPE)
>>> out, err = p.communicate('foo\nfoofoo\n')
>>> print out
foofoo
UWAGA Aaron Hall odpowiedź , która wskazuje, że w niektórych systemach, może trzeba ustawić stdout
, stderr
i stdin
wszystko PIPE
(lub DEVNULL
), aby dostać się communicate
do pracy w ogóle.
W niektórych rzadkich przypadkach może być konieczne przechwytywanie danych wyjściowych w czasie rzeczywistym. Odpowiedź Vartec sugeruje drogę naprzód, ale metody inne niż communicate
podatne na impas, jeśli nie są stosowane ostrożnie.
Podobnie jak w przypadku wszystkich powyższych funkcji, gdy bezpieczeństwo nie stanowi problemu, można uruchamiać bardziej złożone polecenia powłoki, przekazując shell=True
.
Notatki
1. Uruchamianie poleceń powłoki: shell=True
argument
Normalnie, każde wywołanie run
, check_output
lub Popen
konstruktor wykonuje jeden program . Oznacza to, że nie ma żadnych fajnych rur typu bash. Jeśli chcesz uruchamiać złożone polecenia powłoki, możesz przekazać shell=True
, które obsługują wszystkie trzy funkcje.
Takie postępowanie budzi jednak obawy dotyczące bezpieczeństwa . Jeśli robisz coś więcej niż lekkie skrypty, lepiej byłoby wywołać każdy proces osobno i przekazać dane wyjściowe z każdego z nich jako dane wejściowe do następnego, za pośrednictwem
run(cmd, [stdout=etc...], input=other_output)
Lub
Popen(cmd, [stdout=etc...]).communicate(other_output)
Pokusa bezpośredniego połączenia rur jest silna; Oprzeć się. W przeciwnym razie będziesz prawdopodobnie zobaczyć zakleszczenia lub trzeba zrobić hacky rzeczy jak ta .
2. Uwagi dotyczące Unicode
check_output
zwraca ciąg znaków w Python 2, ale bytes
obiekt w Python 3. Warto poświęcić chwilę, aby dowiedzieć się o Unicode, jeśli jeszcze tego nie zrobiłeś.