Podczas korzystania z os.system () często konieczne jest uniknięcie nazw plików i innych argumentów przekazywanych jako parametry do poleceń. W jaki sposób mogę to zrobić? Najlepiej coś, co działałoby na wielu systemach operacyjnych / powłokach, ale w szczególności na bash.
Obecnie wykonuję następujące czynności, ale jestem pewien, że musi to być funkcja biblioteczna lub przynajmniej bardziej elegancka / solidna / wydajna opcja:
def sh_escape(s):
return s.replace("(","\\(").replace(")","\\)").replace(" ","\\ ")
os.system("cat %s | grep something | sort > %s"
% (sh_escape(in_filename),
sh_escape(out_filename)))
Edycja: zaakceptowałem prostą odpowiedź, używając cytatów, nie wiem, dlaczego o tym nie pomyślałem; Chyba dlatego, że pochodzę z systemu Windows, gdzie „i” zachowują się trochę inaczej.
Jeśli chodzi o bezpieczeństwo, rozumiem obawy, ale w tym przypadku interesuje mnie szybkie i łatwe rozwiązanie, które zapewnia os.system (), a źródło ciągów nie jest generowane przez użytkownika lub przynajmniej wprowadzane przez zaufany użytkownik (ja).
sh_escape
funkcja wymknęłaby;
spacje i i usunęłaby problem bezpieczeństwa, po prostu tworząc plik o nazwie coś podobnegofoo.txt\;\ rm\ -rf\ /
.Odpowiedzi:
Oto, czego używam:
Powłoka zawsze akceptuje nazwę pliku w cudzysłowie i usuwa otaczające ją cudzysłowy przed przekazaniem jej do danego programu. Warto zauważyć, że pozwala to uniknąć problemów z nazwami plików, które zawierają spacje lub inne nieprzyjemne metaznaky powłoki.
Aktualizacja : Jeśli korzystasz z Pythona 3.3 lub nowszego, użyj shlex.quote zamiast tworzyć własne.
źródło
shlex
lubpipes
. Te moduły Pythona błędnie zakładają, że znaki specjalne są jedyną rzeczą, która musi być cytowany, co oznacza, że Shell słów kluczowych (jaktime
,case
lubwhile
) będzie analizowany gdy nie oczekuje się, że zachowanie. Z tego powodu zalecałbym użycie procedury pojedynczego cudzysłowu w tej odpowiedzi, ponieważ nie stara się być „sprytna”, więc nie ma tych głupich skrajnych przypadków.shlex.quote()
robi, co chcesz, od Pythona 3.(Służy
pipes.quote
do obsługi języka Python 2 i Python 3)źródło
commands.mkarg
. Dodaje również wiodącą spację (poza cudzysłowami), która może być pożądana lub nie. Ciekawe, jak ich implementacje różnią się od siebie, a także znacznie bardziej skomplikowane niż odpowiedź Grega Hewgilla.pipes.quote
nie ma o tym wzmianki w standardowej dokumentacji biblioteki dla modułu potokówcommand.mkarg
jest przestarzały i usunięty w 3.x, podczas gdy pipe.quote pozostał.shlex.quote()
w 3.3,pipes.quote()
zachowana dla zapewnienia zgodności. [ bugs.python.org/issue9723]Być może masz konkretny powód, dla którego używasz
os.system()
. Ale jeśli nie, prawdopodobnie powinieneś używaćsubprocess
modułu . Możesz określić rury bezpośrednio i uniknąć używania powłoki.Poniższy tekst pochodzi z PEP324 :
źródło
subprocess
(szczególnie zcheck_call
itp.) jest często znacznie lepszy, ale jest kilka przypadków, w których ucieczka pociskiem jest nadal przydatna. Główną rzeczą, z którą się spotykam, jest wywołanie zdalnych poleceń ssh.Może
subprocess.list2cmdline
jest lepszy strzał?źródło
subprocess.list2cmdline(["'",'',"\\",'"'])
daje' "" \ \"
list2cmdline
jest zgodny ze składnią cmd.exe systemu Windows ( zobacz opis funkcji w kodzie źródłowym Pythona ).shlex.quote
jest zgodny ze składnią powłoki bourne w systemie Unix, jednak zwykle nie jest to konieczne, ponieważ Unix ma dobrą obsługę bezpośredniego przekazywania argumentów. Windows prawie wymaga, abyś przekazał pojedynczy łańcuch ze wszystkimi argumentami (stąd potrzeba odpowiedniego znaku ucieczki).Zauważ, że pipe.quote jest faktycznie uszkodzony w Pythonie 2.5 i Pythonie 3.1 i nie jest bezpieczny w użyciu - nie obsługuje argumentów o zerowej długości.
Zobacz wydanie Pythona 7476 ; został naprawiony w Pythonie 2.6 i 3.2 i nowszych.
źródło
Uwaga : to jest odpowiedź dla Pythona 2.7.x.
Według źródła ,
pipes.quote()
jest to sposób na " Rzetelne cytowanie łańcucha jako pojedynczego argumentu dla / bin / sh ". (Chociaż jest przestarzały od wersji 2.7 i ostatecznie ujawniony publicznie w Pythonie 3.3 jakoshlex.quote()
funkcja).Na drugiej strony ,
subprocess.list2cmdline()
jest to sposób na „ Translate sekwencję argumentów na ciąg wiersza poleceń, przy użyciu tych samych zasad jak w czasie wykonywania MS C ”.Oto jesteśmy, niezależny od platformy sposób cytowania ciągów znaków w wierszach poleceń.
Stosowanie:
źródło
Uważam, że os.system po prostu wywołuje dowolną powłokę poleceń skonfigurowaną dla użytkownika, więc nie sądzę, aby można było to zrobić w sposób niezależny od platformy. Moją powłoką poleceń może być wszystko, od bash, emacs, ruby, a nawet quake3. Niektóre z tych programów nie oczekują argumentów, które im przekazujesz, a nawet jeśli to zrobiły, nie ma gwarancji, że uciekną w ten sam sposób.
źródło
Funkcja, której używam, to:
to znaczy: zawsze umieszczam argument w cudzysłowach, a jedyne znaki specjalne w cudzysłowach umieszczam w odwrotnym ukośniku.
źródło
pipes.quote
którą wskazał @JohnWiseman, również jest zepsuta. Zatem odpowiedź Grega Hewgilla jest tą, której należy użyć. (Jest to również ten, którego muszle używają wewnętrznie w zwykłych przypadkach.)Jeśli użyjesz polecenia systemowego, spróbuję umieścić na białej liście to, co wchodzi do wywołania os.system () .. Na przykład ..
Moduł podprocesu jest lepszą opcją i zalecałbym unikanie używania czegoś takiego jak os.system / subprocess, gdy tylko jest to możliwe.
źródło
Prawdziwa odpowiedź brzmi: nie używaj
os.system()
w pierwszej kolejności. Użyjsubprocess.call
zamiast tego i podaj argumenty bez zmiany znaczenia.źródło