Frage

Bei der Verwendung von os.system() ist es häufig erforderlich, Dateinamen und andere Argumente, die als Parameter an Befehle übergeben werden, zu maskieren.Wie kann ich das machen?Am besten etwas, das auf mehreren Betriebssystemen/Shells funktioniert, insbesondere aber für Bash.

Ich mache gerade 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 akzeptiert, Anführungszeichen zu verwenden. Ich weiß nicht, warum ich nicht daran gedacht habe.Ich schätze, weil ich von Windows komme, wo sich ' und " etwas anders verhalten.

Bezüglich der Sicherheit verstehe ich die Bedenken, 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).

War es hilfreich?

Lösung

Das verwende ich:

def shellquote(s):
    return "'" + s.replace("'", "'\\''") + "'"

Die Shell akzeptiert immer einen Dateinamen in Anführungszeichen und entfernt die umgebenden Anführungszeichen, bevor sie ihn an das betreffende Programm übergibt.Dies vermeidet insbesondere Probleme mit Dateinamen, die Leerzeichen oder andere unangenehme Shell-Metazeichen enthalten.

Aktualisieren:Wenn Sie Python 3.3 oder höher verwenden, verwenden Sie shlex.quote anstatt selbst zu rollen.

Andere Tipps

shlex.quote() macht, was Sie wollen, seit Python 3.

(Verwenden pipes.quote um sowohl Python 2 als auch Python 3 zu unterstützen)

Vielleicht haben Sie einen bestimmten Grund für die Verwendung os.system().Aber wenn nicht, sollten Sie wahrscheinlich das verwenden subprocess Modul.Sie können die Pipes direkt angeben und die Verwendung der Shell vermeiden.

Das Folgende ist von PEP324:

Replacing shell pipe line
-------------------------

output=`dmesg | grep hda`
==>
p1 = Popen(["dmesg"], stdout=PIPE)
p2 = Popen(["grep", "hda"], stdin=p1.stdout, stdout=PIPE)
output = p2.communicate()[0]

Vielleicht subprocess.list2cmdline ist ein besserer Schuss?

Beachten Sie, dass „pipes.quote“ in Python 2.5 und Python 3.1 tatsächlich fehlerhaft ist und nicht sicher verwendet werden kann – es verarbeitet keine Argumente der Länge Null.

>>> from pipes import quote
>>> args = ['arg1', '', 'arg3']
>>> print 'mycommand %s' % (' '.join(quote(arg) for arg in args))
mycommand arg1  arg3

Sehen Python-Problem 7476;Es wurde in Python 2.6 und 3.2 und höher behoben.

Ich glaube, dass os.system einfach die für den Benutzer konfigurierte Befehlsshell aufruft, daher glaube ich nicht, dass Sie dies plattformunabhängig tun können.Meine Befehlsshell könnte alles sein, von Bash, Emacs, Ruby oder sogar Quake3.Einige dieser Programme erwarten nicht die Art von Argumenten, die Sie ihnen übergeben, und selbst wenn dies der Fall wäre, gibt es keine Garantie dafür, dass sie auf die gleiche Weise entkommen.

Beachten:Dies ist eine Antwort für Python 2.7.x.

Entsprechend der Quelle, pipes.quote() ist eine Möglichkeit, „Zitieren Sie zuverlässig eine Zeichenfolge als einzelnes Argument für /bin/sh".(Obwohl es so ist seit Version 2.7 veraltet und schließlich in Python 3.3 öffentlich zugänglich gemacht als shlex.quote() Funktion.)

An die andere Hand, subprocess.list2cmdline() ist eine Möglichkeit, „Übersetzen Sie eine Folge von Argumenten in eine Befehlszeilenzeichenfolge und verwenden Sie dabei dieselben Regeln wie die MS C-Laufzeit".

Hier sind wir, die plattformunabhängige Art, Zeichenfolgen für Befehlszeilen zu zitieren.

import sys
mswindows = (sys.platform == "win32")

if mswindows:
    from subprocess import list2cmdline
    quote_args = list2cmdline
else:
    # POSIX
    from pipes import quote

    def quote_args(seq):
        return ' '.join(quote(arg) for arg in seq)

Verwendung:

# Quote a single argument
print quote_args(['my argument'])

# Quote multiple arguments
my_args = ['This', 'is', 'my arguments']
print quote_args(my_args)

Die Funktion, die ich verwende, ist:

def quote_argument(argument):
    return '"%s"' % (
        argument
        .replace('\\', '\\\\')
        .replace('"', '\\"')
        .replace('$', '\\$')
        .replace('`', '\\`')
    )

das ist:Ich schließe das Argument immer in doppelte Anführungszeichen ein und setze dann die einzigen Sonderzeichen innerhalb doppelter Anführungszeichen in Backslash-Anführungszeichen.

Wenn Sie den Systembefehl verwenden, würde ich versuchen, die Inhalte des os.system()-Aufrufs auf die Whitelist zu setzen.Zum Beispiel..

clean_user_input re.sub("[^a-zA-Z]", "", user_input)
os.system("ls %s" % (clean_user_input))

Das Subprocess-Modul ist eine bessere Option, und ich würde empfehlen, die Verwendung von os.system/subprocess nach Möglichkeit zu vermeiden.

Die eigentliche Antwort lautet:Nicht verwenden os.system() an erster Stelle.Verwenden subprocess.call stattdessen und liefern Sie die nicht maskierten Argumente.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top