Jak wywołać zewnętrzne polecenie (tak, jakbym napisał je w powłoce Unixa lub w wierszu poleceń systemu Windows) z poziomu skryptu Python?
4879
Spójrz na moduł podprocesu w standardowej bibliotece:
import subprocess
subprocess.run(["ls", "-l"])
Zaletą subprocess
vs. system
jest to, że jest bardziej elastyczny (można uzyskać stdout
, stderr
, „prawdziwy” kod statusu, lepsza obsługa błędów, itp ...).
Oficjalna dokumentacja zaleca subprocess
moduł nad alternatywą os.system()
:
subprocess
Moduł zapewnia bardziej wydajne urządzenia do tarła nowych procesów i pobierania ich wyników; korzystanie z tego modułu jest lepsze niż używanie tej funkcji [os.system()
].
Do Wymiana Starsze Funkcje z podprocesu Module sekcji w subprocess
dokumentacji może mieć kilka pomocnych recepty.
W przypadku wersji Python wcześniejszych niż 3.5 użyj call
:
import subprocess
subprocess.call(["ls", "-l"])
echo $PATH
za pomocącall(["echo", "$PATH"])
, ale po prostu powtórzyło literalny ciąg$PATH
zamiast dokonywać podstawienia. Wiem, że mogę pobrać zmienną środowiskową PATH, ale zastanawiam się, czy istnieje prosty sposób, aby polecenie zachowywało się dokładnie tak, jakbym wykonał je w trybie bash.shell=True
, aby to zadziałało.shell=True
, w tym celu Python jest dostarczany z os.path.expandvars . W twoim przypadku można napisać:os.path.expandvars("$PATH")
. @SethMMorton proszę ponownie rozważyć swój komentarz -> Dlaczego nie użyć shell = Truefor
pętli, jak to zrobić bez blokowania mojego skryptu python? Nie dbam o wynik polecenia, chcę po prostu uruchomić wiele z nich.subprocess
kiedyshell=False
, a następnie użyj wshlex.split
celu łatwego wykonania tej czynności docs.python.org/2/library/shlex.html#shlex.splitOto podsumowanie sposobów wywoływania programów zewnętrznych oraz zalety i wady każdego z nich:
os.system("some_command with args")
przekazuje polecenie i argumenty do powłoki systemu. Jest to miłe, ponieważ możesz w ten sposób uruchomić wiele poleceń jednocześnie i skonfigurować przekierowania potoków i wejść / wyjść. Na przykład:Jednak, chociaż jest to wygodne, musisz ręcznie obsługiwać zmiany znaczenia znaków powłoki, takich jak spacje itp. Z drugiej strony pozwala to również na uruchamianie poleceń, które są po prostu poleceniami powłoki, a nie programami zewnętrznymi. Zobacz dokumentację .
stream = os.popen("some_command with args")
zrobi to samo coos.system
poza tym, że da ci obiekt podobny do pliku, którego możesz użyć do uzyskania dostępu do standardowego wejścia / wyjścia dla tego procesu. Istnieją 3 inne warianty popen, które nieco inaczej obsługują wejścia / wyjścia. Jeśli przekażesz wszystko jako ciąg, twoje polecenie zostanie przekazane do powłoki; jeśli przekażesz je jako listę, nie musisz się martwić, że coś uciekniesz. Zobacz dokumentację .Popen
Klasasubprocess
modułu. Ma to na celu zastąpienie,os.popen
ale ma tę wadę, że jest nieco bardziej skomplikowane ze względu na to, że jest tak wszechstronne. Na przykład powiedziałbyś:zamiast:
ale fajnie jest mieć wszystkie opcje w jednej zunifikowanej klasie zamiast 4 różnych popenowych funkcji. Zobacz dokumentację .
call
Funkcji zsubprocess
modułu. Jest to w zasadzie tak samo jakPopen
klasa i przyjmuje wszystkie te same argumenty, ale po prostu czeka, aż polecenie się zakończy i poda kod powrotu. Na przykład:Zobacz dokumentację .
Jeśli korzystasz z języka Python 3.5 lub nowszego, możesz użyć nowej
subprocess.run
funkcji, która jest bardzo podobna do powyższej, ale jeszcze bardziej elastyczna i zwracaCompletedProcess
obiekt po zakończeniu wykonywania polecenia.Moduł os posiada również wszystkie funkcje fork / exec / spawn, które miałbyś w programie C, ale nie polecam ich używać bezpośrednio.
subprocess
Moduł powinien prawdopodobnie czego używasz.Na koniec pamiętaj, że dla wszystkich metod, w których przekazujesz ostatnie polecenie do wykonania przez powłokę jako ciąg znaków i jesteś odpowiedzialny za jej ucieczkę. Istnieją poważne konsekwencje dla bezpieczeństwa, jeśli żadna część przekazywanego ciągu nie może być w pełni zaufana. Na przykład, jeśli użytkownik wprowadza jakąś / dowolną część ciągu. Jeśli nie masz pewności, używaj tych metod tylko ze stałymi. Aby dać ci wskazówkę dotyczącą konsekwencji, rozważ ten kod:
i wyobraź sobie, że użytkownik wprowadza coś „moja mama mnie nie kochała && rm -rf /”, co może skasować cały system plików.
źródło
open
.subprocess.run()
. docs.python.org/3.5/library/subprocess.html#subprocess.runsubprocess.run(..)
co dokładnie robi „To domyślnie nie przechwytuje stdout ani stderr”. sugerować? A co zsubprocess.check_output(..)
STDERR?echo
przed ciągiem przekazanym doPopen
? Tak będzie pełne polecenieecho my mama didnt love me && rm -rf /
.subprocess.run()
starszego rodzeństwasubprocess.check_call()
i in. W przypadkach, w których nie wystarczają, patrzsubprocess.Popen()
.os.popen()
nie powinno być wcale wspomniane, ani nawet przychodzić po „zhakowaniu własnego kodu fork / exec / spawn”.Typowa realizacja:
Możesz dowolnie robić z
stdout
danymi w potoku. W rzeczywistości możesz po prostu pominąć te parametry (stdout=
istderr=
) i będzie się tak zachowywałos.system()
.źródło
.readlines()
odczytuje wszystkie wiersze naraz, tzn. blokuje, dopóki podproces nie zakończy działania (nie zamknie końca potoku). Aby czytać w czasie rzeczywistym (jeśli nie ma problemów z buforowaniem), możesz:for line in iter(p.stdout.readline, ''): print line,
p.stdout.readline()
(uwaga: nies
na końcu) nie zobaczy żadnych danych, dopóki dziecko nie zapełni bufora. Jeśli dziecko nie generuje dużych ilości danych, dane wyjściowe nie będą przesyłane w czasie rzeczywistym. Zobacz drugi powód w pytaniu: Dlaczego po prostu nie użyć potoku (popen ())? . Niektóre obejścia są zawarte w tej odpowiedzi (pexpect, pty, stdbuf)Popen
prostych zadań. To również niepotrzebnie określashell=True
. Wypróbuj jedną zsubprocess.run()
odpowiedzi.Kilka wskazówek na temat odłączania procesu potomnego od wywołującego (rozpoczynanie procesu potomnego w tle).
Załóżmy, że chcesz rozpocząć długie zadanie od skryptu CGI. Oznacza to, że proces potomny powinien żyć dłużej niż proces wykonywania skryptu CGI.
Klasyczny przykład z dokumentacji modułu podprocesu to:
Chodzi o to, że nie chcesz czekać w wierszu „wywołanie podprocesu”, aż do zakończenia longtask.py. Ale nie jest jasne, co dzieje się po wierszu „trochę więcej kodu tutaj” z przykładu.
Moją platformą docelową był FreeBSD, ale prace rozwojowe dotyczyły systemu Windows, więc najpierw napotkałem ten problem.
W systemie Windows (Windows XP) proces nadrzędny nie zakończy się, dopóki longtask.py nie zakończy pracy. To nie jest to, czego chcesz w skrypcie CGI. Problem nie jest specyficzny dla Pythona; w społeczności PHP problemy są takie same.
Rozwiązaniem jest przekazanie flagi tworzenia procesu DETACHED_PROCESS do podstawowej funkcji CreateProcess w interfejsie API systemu Windows. Jeśli akurat masz zainstalowany pywin32, możesz zaimportować flagę z modułu win32process, w przeciwnym razie powinieneś ją zdefiniować samodzielnie:
/ * UPD 2015.10.27 @eryksun w komentarzu poniżej zauważa, że semantycznie poprawną flagą jest CREATE_NEW_CONSOLE (0x00000010) * /
Na FreeBSD mamy inny problem: kiedy proces nadrzędny jest zakończony, również kończy procesy potomne. I to nie jest to, czego chcesz w skrypcie CGI. Niektóre eksperymenty wykazały, że problem polegał na udostępnianiu sys.stdout. A działające rozwiązanie było następujące:
Nie sprawdziłem kodu na innych platformach i nie znam przyczyn takiego zachowania na FreeBSD. Jeśli ktoś wie, podziel się swoimi pomysłami. Googling po uruchomieniu procesów w tle w Pythonie nie rzuca jeszcze światła.
źródło
DETACHED_PROCESS
wcreationflags
unika tego poprzez zapobieganie dziecko od dziedziczenia lub tworząc konsolę. Jeśli zamiast tego chcesz nową konsolę, użyjCREATE_NEW_CONSOLE
(0x00000010).os.devnull
ponieważ niektóre programy konsolowe wychodzą z błędem inaczej. Utwórz nową konsolę, jeśli chcesz, aby proces potomny współdziałał z użytkownikiem jednocześnie z procesem nadrzędnym. Byłoby mylące, aby próbować zrobić oba w jednym oknie.Zauważ, że jest to niebezpieczne, ponieważ polecenie nie jest czyszczone. Od Ciebie zależy, czy przejrzysz odpowiednią dokumentację dotyczącą modułów „os” i „sys”. Istnieje kilka funkcji (exec * i spawn *), które zrobią podobne rzeczy.
źródło
subprocess
nieco bardziej wszechstronne i przenośne rozwiązanie. Uruchamianie zewnętrznych poleceń jest oczywiście z natury niesportowalne (musisz upewnić się, że polecenie jest dostępne w każdej architekturze, którą musisz obsługiwać), a przekazywanie danych wejściowych przez użytkownika jako zewnętrzne polecenie jest z natury niebezpieczne.Polecam użycie modułu podprocesu zamiast os.system, ponieważ pozwala on na ucieczkę powłoki i dlatego jest znacznie bezpieczniejszy.
źródło
subprocess
kiedyshell=False
, a następnie użyj wshlex.split
celu łatwego wykonania tego docs.python.org/2/library/shlex.html#shlex.split ( jest to zalecany sposób według docs docs.python.org/2/library/subprocess.html#popen-constructor )Jeśli chcesz zwrócić wyniki polecenia, możesz użyć
os.popen
. Jest to jednak przestarzałe od wersji 2.6 na korzyść modułu podprocesu , który dobrze opisały inne odpowiedzi.źródło
Istnieje wiele różnych bibliotek, które pozwalają na wywoływanie zewnętrznych poleceń za pomocą Pythona. Dla każdej biblioteki podałem opis i pokazałem przykład wywołania zewnętrznego polecenia. Poleceniem, którego użyłem jako przykład, jest
ls -l
(wyświetl wszystkie pliki). Jeśli chcesz dowiedzieć się więcej o którejkolwiek z bibliotek, które wymieniłem i połączyłem dokumentację dla każdej z nich.Mam nadzieję, że pomoże ci to podjąć decyzję, z której biblioteki korzystać :)
Podproces pozwala na wywoływanie zewnętrznych poleceń i podłączanie ich do ich rur wejściowych / wyjściowych / błędów (stdin, stdout i stderr). Podproces jest domyślnym wyborem do uruchamiania poleceń, ale czasem inne moduły są lepsze.
OS służy do „funkcji zależnych od systemu operacyjnego”. Można go również używać do wywoływania zewnętrznych poleceń za pomocą
os.system
ios.popen
(Uwaga: Istnieje również podproces.popen). OS zawsze uruchamia powłokę i jest prostą alternatywą dla osób, które nie muszą lub nie wiedzą, jak używaćsubprocess.run
.sh to interfejs podprocesu, który pozwala wywoływać programy tak, jakby były funkcjami. Jest to przydatne, jeśli chcesz uruchomić polecenie wiele razy.
plumbum to biblioteka dla programów w języku Python przypominających skrypty. Możesz wywoływać programy takie jak funkcje jak w
sh
. Plumbum jest przydatne, jeśli chcesz uruchomić rurociąg bez powłoki.pexpect pozwala spawnować aplikacje potomne, kontrolować je i znajdować wzorce w wynikach. Jest to lepsza alternatywa dla podprocesu dla poleceń, które oczekują tty na Uniksie.
Fabric to biblioteka Python 2.5 i 2.7. Umożliwia wykonywanie lokalnych i zdalnych poleceń powłoki. Struktura jest prostą alternatywą dla uruchamiania poleceń w bezpiecznej powłoce (SSH)
wysłannik jest znany jako „podproces dla ludzi”. Służy jako wygodne opakowanie wokół
subprocess
modułu.commands
zawiera funkcje otoki dlaos.popen
, ale został usunięty z Python 3, ponieważsubprocess
jest lepszą alternatywą.Edycja została oparta na komentarzu JF Sebastiana.
źródło
Zawsze używam
fabric
do takich rzeczy jak:Ale wydaje się, że jest to dobre narzędzie:
sh
(interfejs podprocesu Python) .Spójrz na przykład:
źródło
Sprawdź także bibliotekę Python „pexpect”.
Umożliwia interaktywne sterowanie zewnętrznymi programami / poleceniami, nawet ssh, ftp, telnet itp. Możesz po prostu wpisać coś takiego:
źródło
Ze standardową biblioteką
Użyj modułu podprocesu (Python 3):
Jest to zalecany standardowy sposób. Jednak bardziej skomplikowane zadania (potoki, dane wyjściowe, dane wejściowe itp.) Mogą być uciążliwe w konstruowaniu i pisaniu.
Uwaga na temat wersji Python: Jeśli nadal używasz Python 2, subprocess.call działa w podobny sposób.
Protip: shlex.split może pomóc analizować polecenia dla
run
,call
i innesubprocess
funkcje w przypadku, gdy nie chcą (lub nie!) Udostępnianie ich w formie list:Z zewnętrznymi zależnościami
Jeśli nie masz nic przeciwko zewnętrznym zależnościom, użyj pionu :
To najlepsze
subprocess
opakowanie. Jest wieloplatformowy, tzn. Działa zarówno na systemach Windows, jak i systemach uniksowych. Zainstaluj przezpip install plumbum
.Inną popularną biblioteką jest sh :
Jednak
sh
porzuciłem obsługę systemu Windows, więc nie jest tak niesamowita, jak kiedyś. Zainstaluj przezpip install sh
.źródło
Jeśli potrzebujesz danych wyjściowych z wywoływanej komendy, możesz użyć subprocess.check_output (Python 2.7+).
Zwróć także uwagę na parametr powłoki .
źródło
check_output
wymaga listy, a nie ciągu. Jeśli nie chcesz, aby twoje połączenie było ważne, nie polegaj na cudzysłowach, najprostszym i najbardziej czytelnym sposobem na tosubprocess.check_output("ls -l /dev/null".split())
.W ten sposób uruchamiam moje polecenia. Ten kod zawiera wszystko, czego potrzebujesz
źródło
Aktualizacja:
subprocess.run
jest zalecanym podejściem od wersji Python 3.5, jeśli kod nie musi utrzymywać zgodności z wcześniejszymi wersjami Python. Jest bardziej spójny i oferuje podobną łatwość użycia jak wysłannik. (Rurociągi nie są jednak tak proste. Zobacz to pytanie, jak to zrobić ).Oto kilka przykładów z dokumentacji .
Uruchom proces:
Podnieś po nieudanym biegu:
Przechwytywanie danych wyjściowych:
Oryginalna odpowiedź:
Polecam wypróbowanie Posła . Jest to opakowanie dla podprocesu, który z kolei ma na celu zastąpienie starszych modułów i funkcji. Wysłannik jest procesem dla ludzi.
Przykładowe użycie z README :
Rurociągi też:
źródło
Użyj podprocesu .
... lub dla bardzo prostego polecenia:
źródło
Prosty, użyj
subprocess.run
, który zwracaCompletedProcess
obiekt:Dlaczego?
Począwszy od języka Python 3.5 dokumentacja zaleca subprocess.run :
Oto przykład najprostszego możliwego użycia - i robi to dokładnie tak, jak zapytano:
run
czeka na pomyślne zakończenie polecenia, a następnie zwracaCompletedProcess
obiekt. Zamiast tego może podnieśćTimeoutExpired
(jeśli podasztimeout=
argument) lubCalledProcessError
(jeśli zawiedzie i zdaszcheck=True
).Jak można wywnioskować z powyższego przykładu, stdout i stderr są domyślnie przesyłane do własnego stdout i stderr.
Możemy sprawdzić zwrócony obiekt i zobaczyć wydane polecenie oraz kod powrotu:
Przechwytywanie danych wyjściowych
Jeśli chcesz przechwycić dane wyjściowe, możesz przejść
subprocess.PIPE
do odpowiedniegostderr
lubstdout
:(Uważam za interesujące i nieco sprzeczne z intuicją, że informacje o wersji są ustawiane na stderr zamiast stdout.)
Przekaż listę poleceń
Można łatwo przejść od ręcznego podawania ciągu poleceń (jak sugeruje to pytanie) do dostarczania ciągu zbudowanego programowo. Nie buduj ciągów programowo. Jest to potencjalny problem bezpieczeństwa. Lepiej założyć, że nie ufasz wkładowi.
Uwaga,
args
należy przekazywać tylko pozycyjnie.Pełny podpis
Oto rzeczywisty podpis w źródle i pokazany przez
help(run)
:popenargs
Ikwargs
są przekazywane doPopen
konstruktora.input
może być ciągiem bajtów (lub Unicode, jeśli określono kodowanie lubuniversal_newlines=True
), które będą przesyłane do standardowego wejścia podprocesu.Dokumentacja opisuje
timeout=
icheck=True
lepiej niż mogłem:i ten przykład
check=True
jest lepszy niż ten, który mógłbym wymyślić:Rozszerzony podpis
Oto rozwinięty podpis, jak podano w dokumentacji:
Zauważ, że oznacza to, że tylko lista argumentów powinna być przekazywana pozycyjnie. Przekaż pozostałe argumenty jako argumenty słów kluczowych.
Popen
Kiedy
Popen
zamiast tego użyć ? Z trudem znajdowałbym przypadek użycia na podstawie samych argumentów. Bezpośrednie użyciePopen
daje jednak dostęp do jego metod, w tympoll
„send_signal”, „terminate” i „wait”.Oto
Popen
podpis podany w źródle . Myślę, że jest to najbardziej precyzyjna enkapsulacja informacji (w przeciwieństwie dohelp(Popen)
):Ale bardziej pouczające jest dokumentacja :
Popen
Zrozumienie pozostałej dokumentacji
Popen
zostanie pozostawione jako ćwiczenie dla czytelnika.źródło
shell=True
(lub jeszcze lepiej) przekazać polecenie jako listę.os.system
jest OK, ale trochę przestarzałe. To również nie jest bardzo bezpieczne. Zamiast tego spróbujsubprocess
.subprocess
nie wywołuje sh bezpośrednio i dlatego jest bezpieczniejszy niżos.system
.Uzyskaj więcej informacji tutaj .
źródło
subprocess
nie usuwa wszystkich problemów związanych z bezpieczeństwem i ma pewne nieznośne problemy.Jest też Plumbum
źródło
Posługiwać się:
os - ten moduł zapewnia przenośny sposób korzystania z funkcji zależnych od systemu operacyjnego.
Dla bardziej
os
funkcji, tutaj jest dokumentacja.źródło
Może to być takie proste:
źródło
os.system
wyraźnie zaleca unikanie tego na korzyśćsubprocess
.Bardzo podoba mi się shell_command ze względu na jego prostotę. Jest zbudowany na module podprocesu.
Oto przykład z dokumentacji:
źródło
Jest jeszcze jedna różnica, o której wcześniej nie wspomniano.
subprocess.Popen
wykonuje <polecenie> jako podproces. W moim przypadku muszę wykonać plik <a>, który musi komunikować się z innym programem, <b>.Próbowałem podprocesu i wykonanie zakończyło się powodzeniem. Jednak <b> nie mógł komunikować się z <a>. Wszystko działa normalnie, gdy uruchamiam oba z terminala.
Jeszcze jedno: (UWAGA: kwrite zachowuje się inaczej niż inne aplikacje. Jeśli wypróbujesz poniższe ustawienia w przeglądarce Firefox, wyniki nie będą takie same.)
Jeśli spróbujesz
os.system("kwrite")
, przepływ programu zawiesza się, dopóki użytkownik nie zamknie kwrite. Żeby to pokonać, próbowałem zamiast tegoos.system(konsole -e kwrite)
. Ten program czasowy nadal płynął, ale kwrite stał się podprocesem konsoli.Każdy uruchamia kwrite, który nie jest podprocesem (tzn. Na monitorze systemu musi pojawiać się na skrajnej lewej krawędzi drzewa).
źródło
os.system
nie pozwala na przechowywanie wyników, więc jeśli chcesz zapisać wyniki na jakiejś liście lub coś,subprocess.call
działa.źródło
subprocess.check_call
jest wygodny, jeśli nie chcesz testować zwracanych wartości. Zgłasza wyjątek dla każdego błędu.źródło
Zwykle używam podprocesu razem z shlex (do obsługi ucieczki cytowanych ciągów):
źródło
Bezwstydna wtyczka, napisałem bibliotekę dla tego: P https://github.com/houqp/shell.py
Na razie jest to po prostu opakowanie na popen i shlex. Obsługuje także polecenia potokowe, dzięki czemu można łatwiej łączyć łańcuchy poleceń w języku Python. Możesz więc robić takie rzeczy jak:
źródło
W systemie Windows można po prostu zaimportować
subprocess
moduł i uruchomić zewnętrznych poleceń poprzez wywołaniesubprocess.Popen()
,subprocess.Popen().communicate()
asubprocess.Popen().wait()
jak poniżej:Wynik:
źródło
W systemie Linux, jeśli chcesz wywołać zewnętrzną komendę, która wykona się niezależnie (będzie działać po zakończeniu skryptu python), możesz użyć prostej kolejki jako buforu zadań lub komendy at
Przykład z buforem zadań:
Uwagi na temat buforowania zadań (
ts
):Możesz ustawić liczbę równoległych procesów do uruchomienia („slotów”) za pomocą:
ts -S <number-of-slots>
Instalacja
ts
nie wymaga uprawnień administratora. Możesz pobrać i skompilować go ze źródła w prosty sposóbmake
, dodać go do swojej ścieżki i gotowe.źródło
ts
nie jest standardem w żadnej znanej dystrybucji, chociaż wskaźnik doat
jest raczej przydatny. Prawdopodobnie powinieneś również wspomniećbatch
. Podobnie jak gdzie indziej,os.system()
zalecenie powinno przynajmniej zawierać wzmiankę osubprocess
zalecanym zastąpieniu.Możesz użyć Popen, a następnie możesz sprawdzić status procedury:
Sprawdź podproces . Otwórz .
źródło
Aby pobrać identyfikator sieci z OpenStack Neutron :
Wyjście nova netto liście
Wyjście wydruku (networkId)
źródło
os.popen()
w 2016 roku. Skrypt Awk można łatwo zastąpić rodzimym kodem Python.