Lorsque vous utilisez 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)))
Edit: j'ai accepté la réponse simple d'utiliser des guillemets, je ne sais pas pourquoi je n'y ai pas pensé; Je suppose que parce que je suis venu de Windows où «et» se comportent un peu différemment.
En ce qui concerne la sécurité, je comprends le problème, mais, dans ce cas, je suis intéressé par une solution rapide et facile fournie par os.system (), et la source des chaînes n'est pas générée par l'utilisateur ou du moins saisie par un utilisateur de confiance (moi).
sh_escape
fonction idéale échapperait aux;
espaces et et éliminerait le problème de sécurité en créant simplement un fichier appelé quelque chose commefoo.txt\;\ rm\ -rf\ /
.Réponses:
Voici ce que j'utilise:
Le shell acceptera toujours un nom de fichier entre guillemets et supprimera les guillemets environnants avant de le transmettre au programme en question. Notamment, cela évite les problèmes avec les noms de fichiers contenant des espaces ou tout autre type de métacaractère de coquille désagréable.
Mettre à jour : si vous utilisez Python 3.3 ou version ultérieure, utilisez shlex.quote au lieu de lancer le vôtre.
la source
shlex
oupipes
. Ces modules python supposent à tort que les caractères spéciaux sont la seule chose qui doit être entre guillemets, ce qui signifie que les mots-clés du shell (commetime
,case
ouwhile
) seront analysés lorsque ce comportement n'est pas attendu. Pour cette raison, je recommanderais d'utiliser la routine de guillemets simples dans cette réponse, car elle n'essaie pas d'être "intelligente" et n'a donc pas ces cas extrêmes.shlex.quote()
fait ce que vous voulez depuis python 3.(Utilisez
pipes.quote
pour prendre en charge à la fois python 2 et python 3)la source
commands.mkarg
. Il ajoute également un espace de début (en dehors des guillemets) qui peut être souhaitable ou non.Il est intéressant de voir comment leurs implémentations sont assez différentes les unes des autres, et aussi beaucoup plus compliquées que la réponse de Greg Hewgill.pipes.quote
n'est pas mentionné par la documentation standard de la bibliothèque pour le module pipescommand.mkarg
est obsolète et supprimée dans 3.x, tandis que pipes.quote est resté.shlex.quote()
en 3.3,pipes.quote()
conservé pour compatibilité. [ bugs.python.org/issue9723]Peut-être avez-vous une raison spécifique d'utiliser
os.system()
. Mais sinon, vous devriez probablement utiliser lesubprocess
module . Vous pouvez spécifier les tuyaux directement et éviter d'utiliser la coque.Ce qui suit est de PEP324 :
la source
subprocess
(en particulier aveccheck_call
etc.) est souvent considérablement supérieur, mais il y a quelques cas où l'échappement du shell est toujours utile. Le principal que je rencontre est lorsque je dois appeler des commandes à distance ssh.Peut
subprocess.list2cmdline
- être est-ce un meilleur coup?la source
subprocess.list2cmdline(["'",'',"\\",'"'])
donne' "" \ \"
list2cmdline
conforme à la syntaxe Windows cmd.exe ( voir la fonction docstring dans le code source Python ).shlex.quote
est conforme à la syntaxe du shell bourne d'Unix, mais ce n'est généralement pas nécessaire car Unix a un bon support pour passer directement des arguments. Windows nécessite à peu près que vous passiez une seule chaîne avec tous vos arguments (donc la nécessité d'un échappement approprié).Notez que pipes.quote est en fait cassé 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.
Voir le numéro 7476 de Python ; il a été corrigé dans Python 2.6 et 3.2 et plus récents.
la source
Remarque : Ceci est une réponse pour Python 2.7.x.
Selon la source ,
pipes.quote()
est un moyen de " citer de manière fiable une chaîne comme argument unique pour / bin / sh ". (Bien qu'il soit obsolète depuis la version 2.7 et finalement exposé publiquement dans Python 3.3 en tant queshlex.quote()
fonction.)D' autre part ,
subprocess.list2cmdline()
est un moyen de " Traduire une séquence d'arguments en une chaîne de ligne de commande, en utilisant les mêmes règles que le runtime MS C ".Nous voici, la manière indépendante de la plate-forme de citer des chaînes pour les lignes de commande.
Usage:
la source
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 d'une manière indépendante de la plate-forme. Mon shell de commande peut être n'importe quoi de bash, emacs, ruby ou même quake3. Certains de ces programmes n'attendent pas le type d'arguments que vous leur transmettez et même s'ils le faisaient, il n'y a aucune garantie qu'ils échappent de la même manière.
la source
La fonction que j'utilise est:
c'est-à-dire: je place toujours l'argument entre des guillemets doubles, puis je cite les seuls caractères spéciaux entre guillemets doubles.
la source
pipes.quote
que @JohnWiseman a souligné est également cassée. La réponse de Greg Hewgill est donc celle à utiliser. (C'est aussi celui que les coquilles utilisent en interne pour les cas normaux.)Si vous utilisez la commande système, j'essaierais de mettre en liste blanche ce qui entre dans l'appel os.system () .. Par exemple ..
Le module de sous-processus est une meilleure option, et je recommanderais d'essayer d'éviter d'utiliser quelque chose comme os.system / subprocess dans la mesure du possible.
la source
La vraie réponse est: ne pas utiliser
os.system()
en premier lieu. Utilisez à lasubprocess.call
place et fournissez les arguments sans échappement.la source