Odpowiedź na to pytanie zależy od używanej wersji języka Python. Najprostszym podejściem jest użycie subprocess.check_outputfunkcji:
>>> subprocess.check_output(['ls', '-l'])
b'total 0\n-rw-r--r-- 1 memyself staff 0 Mar 14 11:04 files\n'
check_outputuruchamia 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 runlub Popen. Jeśli chcesz wykonywać złożone polecenia powłoki, zobacz uwagę na shell=Truekońcu tej odpowiedzi.
Ta check_outputfunkcja 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 runfunkcja jest zalecana. Zapewnia bardzo ogólny interfejs API wysokiego poziomu dla subprocessmodułu. Aby przechwycić dane wyjściowe programu, przekaż subprocess.PIPEflagę do stdoutargumentu słowa kluczowego. Następnie uzyskaj dostęp do stdoutatrybutu zwróconego CompletedProcessobiektu:
>>> 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 bytesobiekt, więc jeśli potrzebujesz odpowiedniego ciągu, musisz decodego. 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ż bytesobiekt do inputargumentu 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.stdoutwraz 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=Truezgodnie 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 runsamą 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_outputfunkcji 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_outputjest równoważne wykonywaniu za runpomocą check=Truei stdout=PIPEi zwracaniu tylko stdoutatrybutu.
Możesz przekazać, stderr=subprocess.STDOUTaby upewnić się, że komunikaty o błędach są uwzględnione w zwróconych danych wyjściowych - ale w niektórych wersjach przekazywanie stderr=subprocess.PIPEdo Pythona check_outputmoże powodować zakleszczenia . Gdy bezpieczeństwo nie stanowi problemu, możesz także uruchamiać bardziej złożone polecenia powłoki, przekazując shell=Truezgodnie z opisem w uwagach poniżej.
Jeśli potrzebujesz potokować stderrlub przekazywać dane wejściowe do procesu, check_outputnie będzie to do zadania. PopenW 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_outputzapewnia, będziesz musiał pracować bezpośrednio z Popenobiektami, które zawierają niskopoziomowy interfejs API dla podprocesów.
PopenKonstruktor 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.splitmoże pomóc w analizie ciągów znaków w odpowiednio sformatowanych listach. Popenobiekty 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 communicatejest 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, communicatepozwala 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, stderri stdinwszystko PIPE(lub DEVNULL), aby dostać się communicatedo 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ż communicatepodatne 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=Trueargument
Normalnie, każde wywołanie run, check_outputlub Popenkonstruktor 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_outputzwraca ciąg znaków w Python 2, ale bytesobiekt w Python 3. Warto poświęcić chwilę, aby dowiedzieć się o Unicode, jeśli jeszcze tego nie zrobiłeś.