Z subprocess
modułem wywołuję różne procesy . Mam jednak pytanie.
W następujących kodach:
callProcess = subprocess.Popen(['ls', '-l'], shell=True)
i
callProcess = subprocess.Popen(['ls', '-l']) # without shell
Oba działają. Po przeczytaniu dokumentacji dowiedziałem się, że shell=True
oznacza to wykonanie kodu przez powłokę. Oznacza to, że w przypadku nieobecności proces rozpoczyna się bezpośrednio.
Więc co powinienem preferować w moim przypadku - muszę uruchomić proces i uzyskać jego wynik. Jakie korzyści czerpię z wywoływania go z poziomu powłoki lub poza nią.
python
subprocess
użytkownik225312
źródło
źródło
-l
jest przekazywane do/bin/sh
(powłoki) zamiastls
programu w Uniksie, jeślishell=True
.shell=True
W większości przypadków należy użyć argumentu ciągu zamiast listy.shell=True
celuFalse
i vice versa jest błąd. Z dokumentacji : „W systemie POSIX z powłoką = prawda (...) Jeśli argument jest sekwencją, pierwszy element określa ciąg polecenia, a wszelkie dodatkowe elementy będą traktowane jako dodatkowe argumenty do samej powłoki.”. W systemie Windows istnieje automatyczna konwersja , która może być niepożądana.Odpowiedzi:
Zaletą nie wywoływania przez powłokę jest to, że nie wywołujesz „tajemniczego programu”. W POSIX zmienna środowiskowa
SHELL
kontroluje, który plik binarny jest wywoływany jako „powłoka”. W systemie Windows nie ma potomka powłoki Bourne'a, tylko cmd.exe.Wywołanie powłoki wywołuje więc program wybrany przez użytkownika i zależy od platformy. Ogólnie rzecz biorąc, unikaj wywołań za pośrednictwem powłoki.
Wywoływanie za pośrednictwem powłoki umożliwia rozszerzanie zmiennych środowiskowych i globów plików zgodnie ze zwykłym mechanizmem powłoki. W systemach POSIX powłoka rozszerza globusy plików do listy plików. W systemie Windows glob pliku (np. „*. *”) I tak nie jest rozszerzany przez powłokę (ale zmienne środowiskowe w wierszu poleceń są rozwijane przez cmd.exe).
Jeśli uważasz, że chcesz rozszerzeń zmiennych środowiskowych i globów plików, sprawdź
ILS
ataki z 1992 roku na usługi sieciowe, które wykonały wywołania podprogramów za pośrednictwem powłoki. Przykłady obejmują różnesendmail
zaangażowane backdooryILS
.Podsumowując, użyj
shell=False
.źródło
$SHELL
jest niepoprawne. Cytując subprocess.html: „W Uniksie zshell=True
domyślną powłoką jest/bin/sh
.” (nie$SHELL
)open
jeśli chcesz w bezpieczny sposób wywołać program i przechwycić dane wyjściowe.źródło: Moduł podprocesu
źródło
Tutaj pokazano przykład, w którym coś może pójść nie tak z Shell = True
Sprawdź dokument tutaj: subprocess.call ()
źródło
Wykonywanie programów przez powłokę oznacza, że wszystkie dane wejściowe użytkownika przekazywane do programu są interpretowane zgodnie ze składnią i regułami semantycznymi wywoływanej powłoki. W najlepszym wypadku powoduje to tylko niedogodności dla użytkownika, ponieważ użytkownik musi przestrzegać tych zasad. Na przykład ścieżki zawierające specjalne znaki powłoki, takie jak cudzysłów lub spacje, muszą być poprzedzone znakami ucieczki. W najgorszym przypadku powoduje wyciek bezpieczeństwa, ponieważ użytkownik może wykonywać dowolne programy.
shell=True
czasem jest wygodne korzystanie z określonych funkcji powłoki, takich jak dzielenie słów lub rozwijanie parametrów. Jeśli jednak taka funkcja jest wymagana, skorzystaj z innych modułów, które otrzymałeś (np. Wos.path.expandvars()
celu rozszerzenia parametrów lubshlex
podziału słów). Oznacza to więcej pracy, ale pozwala uniknąć innych problemów.W skrócie: Unikaj
shell=True
za wszelką cenę.źródło
Pozostałe odpowiedzi w odpowiedni sposób wyjaśniają zastrzeżenia bezpieczeństwa, które są również wymienione w
subprocess
dokumentacji. Ale oprócz tego narzut związany z uruchomieniem powłoki w celu uruchomienia programu, który chcesz uruchomić, jest często niepotrzebny i zdecydowanie głupi w sytuacjach, w których nie używasz żadnej z funkcji powłoki. Co więcej, dodatkowa ukryta złożoność powinna cię wystraszyć, szczególnie jeśli nie znasz dobrze powłoki lub usług, które ona zapewnia.Tam, gdzie interakcje z powłoką są nietrywialne, musisz teraz czytać i utrzymywać skrypt Pythona (który może, ale nie musi być twoim przyszłym ja), aby zrozumieć zarówno Python, jak i skrypt powłoki. Pamiętaj motto Pythona „wyraźne jest lepsze niż niejawne”; nawet jeśli kod Pythona będzie nieco bardziej skomplikowany niż równoważny (i często bardzo zwięzły) skrypt powłoki, lepiej jest usunąć powłokę i zastąpić funkcjonalność natywnymi konstrukcjami Pythona. Minimalizowanie pracy wykonanej w procesie zewnętrznym i utrzymywanie kontroli nad własnym kodem w miarę możliwości jest często dobrym pomysłem, ponieważ poprawia widoczność i zmniejsza ryzyko pożądanych lub niepożądanych efektów ubocznych.
Rozszerzanie symboli wieloznacznych, interpolacja zmiennych i przekierowanie można łatwo zastąpić natywnymi konstrukcjami języka Python. Złożony potok powłoki, w którym części lub wszystkich nie można w rozsądny sposób przepisać w Pythonie, byłby jedyną sytuacją, w której można rozważyć użycie powłoki. Nadal upewnij się, że rozumiesz wpływ na wydajność i bezpieczeństwo.
W trywialnym przypadku, aby tego uniknąć
shell=True
, wystarczy wymienićz
Zauważ, że pierwszym argumentem jest lista ciągów, które należy przekazać
execvp()
, i w jaki sposób cytowanie ciągów i metaznaków powłoki odwracających ukośnik nie jest generalnie konieczne (ani przydatne, ani poprawne). Może zobacz także Kiedy zawijać cudzysłowy wokół zmiennej powłoki?Nawiasem mówiąc, bardzo często chcesz uniknąć,
Popen
jeśli jeden z prostszych opakowań wsubprocess
pakiecie robi to, co chcesz. Jeśli masz dość najnowszego Pythona, prawdopodobnie powinieneś go użyćsubprocess.run
.check=True
nie powiedzie się, jeśli uruchomione polecenie nie powiedzie się.stdout=subprocess.PIPE
niemu przechwyci wynik polecenia.universal_newlines=True
niemu dekoduje dane wyjściowe do odpowiedniego łańcucha Unicode (inaczej jest to tylkobytes
systemowe kodowanie w Pythonie 3).Jeśli nie, w przypadku wielu zadań chcesz
check_output
uzyskać dane wyjściowe z polecenia, sprawdzając, czy się powiodło, lubcheck_call
czy nie ma danych wyjściowych do zebrania.Zakończę cytatem Davida Korna: „Łatwiej jest napisać przenośną powłokę niż przenośny skrypt powłoki”. Nawet
subprocess.run('echo "$HOME"', shell=True)
nie jest przenośny na Windows.źródło
shell=True
, wiele z doskonałymi odpowiedziami. Zdarzyło ci się wybrać ten, który dotyczy tego zamiast tego.subprocess