Bei Verwendung von os.system () müssen häufig Dateinamen und andere Argumente maskiert werden, die als Parameter an Befehle übergeben werden. Wie kann ich das machen? Am besten etwas, das auf mehreren Betriebssystemen / Shells funktioniert, aber insbesondere für Bash.
Ich mache derzeit Folgendes, bin mir aber sicher, dass es dafür eine Bibliotheksfunktion oder zumindest eine elegantere / robustere / effizientere Option geben muss:
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)))
Bearbeiten: Ich habe die einfache Antwort der Verwendung von Anführungszeichen akzeptiert, weiß nicht, warum ich nicht daran gedacht habe; Ich denke, weil ich von Windows kam, wo 'und "sich ein wenig anders verhalten.
In Bezug auf die Sicherheit verstehe ich das Problem, aber in diesem Fall bin ich an einer schnellen und einfachen Lösung interessiert, die os.system () bietet, und die Quelle der Zeichenfolgen wird entweder nicht vom Benutzer generiert oder zumindest von a eingegeben vertrauenswürdiger Benutzer (ich).
sh_escape
Funktion würde aus den;
Leerzeichen und entkommen und das Sicherheitsproblem beseitigen, indem einfach eine Datei mit dem Namen "so etwas" erstellt wirdfoo.txt\;\ rm\ -rf\ /
.Antworten:
Das benutze ich:
Die Shell akzeptiert immer einen Dateinamen in Anführungszeichen und entfernt die umgebenden Anführungszeichen, bevor sie an das betreffende Programm übergeben wird. Dies vermeidet insbesondere Probleme mit Dateinamen, die Leerzeichen oder andere böse Shell-Metazeichen enthalten.
Update : Wenn Sie Python 3.3 oder höher verwenden, verwenden Sie shlex.quote, anstatt Ihre eigene zu rollen.
quelle
shlex
oderpipes
. Diese Python - Module übernehmen fälschlicherweise , dass Sonderzeichen die einzige Sache sind , die notiert werden müssen, die Mittel , die Schlüsselwörter Shell (wietime
,case
oderwhile
) wird analysiert werden , wenn dieses Verhalten nicht zu erwarten ist. Aus diesem Grund würde ich empfehlen, in dieser Antwort die Routine mit einfachen Anführungszeichen zu verwenden, da sie nicht versucht, "klug" zu sein, also keine dummen Randfälle hat.shlex.quote()
macht was du willst seit python 3.(Verwenden Sie
pipes.quote
diese Option , um sowohl Python 2 als auch Python 3 zu unterstützen.)quelle
commands.mkarg
. Es wird auch ein führender Bereich (außerhalb der Anführungszeichen) hinzugefügt, der wünschenswert oder nicht wünschenswert sein kann. Es ist interessant, wie unterschiedlich ihre Implementierungen voneinander sind und auch viel komplizierter als Greg Hewgills Antwort.pipes.quote
wird in der Standardbibliotheksdokumentation für das Rohrmodulcommand.mkarg
wird in 3.x veraltet und entfernt, während pipes.quote erhalten bleibt.shlex.quote()
in 3.3,pipes.quote()
aus Kompatibilitätsgründen beibehalten. [ bugs.python.org/issue9723]Vielleicht haben Sie einen bestimmten Grund für die Verwendung
os.system()
. Wenn nicht, sollten Sie dassubprocess
Modul wahrscheinlich verwenden . Sie können die Pipes direkt angeben und die Verwendung der Shell vermeiden.Folgendes stammt aus PEP324 :
quelle
subprocess
(besonders beicheck_call
usw.) ist oft dramatisch überlegen, aber es gibt einige Fälle, in denen das Entweichen der Schale immer noch nützlich ist. Das wichtigste, auf das ich stoße, ist, wenn ich ssh-Fernbefehle aufrufen muss.Vielleicht
subprocess.list2cmdline
ist ein besserer Schuss?quelle
subprocess.list2cmdline(["'",'',"\\",'"'])
gibt' "" \ \"
list2cmdline
entspricht der Windows-Syntax cmd.exe ( siehe Funktion docstring im Python-Quellcode ).shlex.quote
entspricht der Unix-Bourne-Shell-Syntax, ist jedoch normalerweise nicht erforderlich, da Unix die direkte Übergabe von Argumenten gut unterstützt. Windows erfordert so ziemlich, dass Sie eine einzelne Zeichenfolge mit all Ihren Argumenten übergeben (daher ist ein ordnungsgemäßes Escapezeichen erforderlich).Beachten Sie, dass pipes.quote in Python 2.5 und Python 3.1 tatsächlich fehlerhaft und nicht sicher zu verwenden ist. Es werden keine Argumente mit der Länge Null verarbeitet.
Siehe Python-Ausgabe 7476 ; Es wurde in Python 2.6 und 3.2 und höher behoben.
quelle
Hinweis : Dies ist eine Antwort für Python 2.7.x.
Laut der Quelle gibt
pipes.quote()
es eine Möglichkeit, " einen String zuverlässig als einzelnes Argument für / bin / sh zu zitieren ". (Obwohl es seit Version 2.7 veraltet ist und schließlich öffentlich in Python 3.3 alsshlex.quote()
Funktion verfügbar gemacht wurde .)Auf der anderen Seite gibt
subprocess.list2cmdline()
es eine Möglichkeit, " eine Folge von Argumenten in eine Befehlszeilenzeichenfolge zu übersetzen, wobei dieselben Regeln wie für die MS C-Laufzeit verwendet werden ".Hier sind wir, die plattformunabhängige Methode zum Zitieren von Zeichenfolgen für Befehlszeilen.
Verwendung:
quelle
Ich glaube, dass os.system nur die für den Benutzer konfigurierte Befehlsshell aufruft, daher glaube ich nicht, dass Sie dies plattformunabhängig tun können. Meine Befehlsshell kann alles von Bash, Emacs, Ruby oder sogar Quake3 sein. Einige dieser Programme erwarten nicht die Art von Argumenten, die Sie an sie weitergeben, und selbst wenn dies der Fall ist, gibt es keine Garantie dafür, dass sie auf die gleiche Weise entkommen.
quelle
Die Funktion, die ich benutze, ist:
Das heißt: Ich füge das Argument immer in doppelte Anführungszeichen ein und zitiere dann die einzigen Sonderzeichen in doppelten Anführungszeichen.
quelle
pipes.quote
den @JohnWiseman hingewiesen hat, ist ebenfalls fehlerhaft. Greg Hewgills Antwort ist daher die zu verwendende. (Es ist auch die, die die Muscheln intern für die regulären Fälle verwenden.)Wenn Sie den Systembefehl verwenden, würde ich versuchen, eine Whitelist für den Aufruf von os.system () zu erstellen. Zum Beispiel.
Das Unterprozessmodul ist eine bessere Option, und ich würde empfehlen, die Verwendung von os.system / subprocess nach Möglichkeit zu vermeiden.
quelle
Die wirkliche Antwort lautet: Nicht
os.system()
in erster Linie verwenden. Verwenden Siesubprocess.call
stattdessen und geben Sie die nicht entkoppelten Argumente an.quelle