Question

Lors de l'utilisation de os.system(), il est souvent nécessaire d'échapper aux noms de fichiers et autres arguments passés en paramètres aux commandes.Comment puis-je faire ceci?De préférence quelque chose qui fonctionnerait sur plusieurs systèmes d'exploitation/shells mais en particulier pour bash.

Je fais actuellement ce qui suit, mais je suis sûr qu'il doit y avoir une fonction de bibliothèque pour cela, ou au moins une option plus élégante/robuste/efficace :

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)))

Modifier: J'ai accepté la réponse simple consistant à utiliser des guillemets, je ne sais pas pourquoi je n'y ai pas pensé ;Je suppose que parce que je viens de Windows où « et » se comportent un peu différemment.

Concernant la sécurité, je comprends le souci, mais, dans ce cas, je suis intéressé par une solution rapide et simple fournie par os.system(), et la source des chaînes n'est pas générée par l'utilisateur ou au moins saisie par un utilisateur de confiance (moi).

Était-ce utile?

La solution

Voici ce que j'utilise :

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

Le shell acceptera toujours un nom de fichier entre guillemets et supprimera les guillemets environnants avant de le transmettre au programme en question.Cela évite notamment les problèmes avec les noms de fichiers contenant des espaces ou tout autre type de métacaractère shell malveillant.

Mise à jour:Si vous utilisez Python 3.3 ou version ultérieure, utilisez shlex.quote au lieu de rouler le vôtre.

Autres conseils

shlex.quote() fait ce que vous voulez depuis python 3.

(Utiliser pipes.quote pour prendre en charge à la fois python 2 et python 3)

Peut-être avez-vous une raison spécifique d'utiliser os.system().Mais sinon, vous devriez probablement utiliser le subprocess module.Vous pouvez spécifier les tuyaux directement et éviter d'utiliser le shell.

Ce qui suit est de 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]

Peut être subprocess.list2cmdline est-ce qu'un meilleur coup est fait ?

Notez que pipes.quote est en fait interrompu dans Python 2.5 et Python 3.1 et n'est pas sûr à utiliser : il ne gère pas les arguments de longueur nulle.

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

Voir Problème Python 7476;il a été corrigé dans Python 2.6 et 3.2 et versions ultérieures.

Je crois que os.system appelle simplement le shell de commande configuré pour l'utilisateur, donc je ne pense pas que vous puissiez le faire de manière indépendante de la plate-forme.Mon shell de commande peut être n'importe quoi, bash, emacs, ruby ​​ou même quake3.Certains de ces programmes ne s'attendent pas au genre d'arguments que vous leur transmettez et même s'ils le faisaient, il n'y a aucune garantie qu'ils s'en sortiront de la même manière.

Avis:Ceci est une réponse pour Python 2.7.x.

Selon le source, pipes.quote() est un moyen de "Citer de manière fiable une chaîne comme argument unique pour /bin/sh".(Même si c'est obsolète depuis la version 2.7 et finalement exposé publiquement dans Python 3.3 en tant que shlex.quote() fonction.)

Sur l'autre main, subprocess.list2cmdline() est un moyen de "Traduisez une séquence d'arguments en une chaîne de ligne de commande, en utilisant les mêmes règles que Exécution MS C".

Nous voici, la manière indépendante de la plate-forme de citer des chaînes pour les lignes de commande.

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)

Usage:

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

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

La fonction que j'utilise est :

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

c'est-à-dire:Je mets toujours l'argument entre guillemets doubles, puis je cite les seuls caractères spéciaux entre guillemets doubles.

Si vous utilisez la commande système, j'essaierais de mettre sur liste blanche ce qui entre dans l'appel os.system().Par exemple..

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

Le module subprocess est une meilleure option, et je recommanderais d'essayer d'éviter d'utiliser quelque chose comme os.system/subprocess autant que possible.

La vraie réponse est :Ne pas utiliser os.system() en premier lieu.Utiliser subprocess.call à la place et fournissez les arguments non échappés.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top