web-dev-qa-db-fra.com

Échapper à des citations doubles dans un script de lot

Comment pourrais-je remplacer toutes les guillemets doubles dans les paramètres de mon fichier de traitement par des guillemets d'échappement? Ceci est mon fichier de commandes actuel, qui développe tous ses paramètres de ligne de commande dans la chaîne:

@echo off
call bash --verbose -c "g++-linux-4.1 %*"

Il utilise ensuite cette chaîne pour appeler le bash de Cygwin, en exécutant un compilateur croisé Linux. Malheureusement, je reçois des paramètres comme ceux-ci passés dans mon fichier batch:

"launch-linux-g++.bat" -ftemplate-depth-128 -O3 -finline-functions 
-Wno-inline -Wall  -DNDEBUG   -c 
-o "C:\Users\Me\Documents\Testing\SparseLib\bin\Win32\LinuxRelease\hello.o" 
"c:\Users\Me\Documents\Testing\SparseLib\SparseLib\hello.cpp"

Où le premier guillemet autour du premier chemin emprunté met fin prématurément à la chaîne transmise à GCC, et transmet le reste des paramètres directement à bash (ce qui échoue de manière spectaculaire.)

J'imagine que si je peux concaténer les paramètres dans une seule chaîne, puis échapper aux guillemets, tout devrait bien fonctionner, mais j'ai du mal à déterminer comment procéder. Est-ce que quelqu'un sait?

81
eplawless

Google a finalement trouvé la réponse. La syntaxe pour le remplacement de chaîne en batch est la suivante:

set v_myvar=replace me
set v_myvar=%v_myvar:ace=icate%

Ce qui produit "réplique moi". Mon script ressemble maintenant à ceci:

@echo off
set v_params=%*
set v_params=%v_params:"=\"%
call bash -c "g++-linux-4.1 %v_params%"

Qui remplace toutes les instances de " avec \", échappé correctement pour Bash.

22
eplawless

Le caractère d'échappement dans les scripts batch est ^. Mais pour les chaînes entre guillemets, doublez les guillemets:

"string with an embedded "" character"
92
Eclipse

En complément de excellente réponse de mklement :

Presque tous les exécutables acceptent \" comme un évadé ". L'utilisation sécurisée dans cmd est cependant presque uniquement possible avec DELAYEDEXPANSION.
Pour envoyer explicitement un littéral " à un processus, attribuez \" à une variable d’environnement, puis utilisez cette variable chaque fois que vous devez transmettre un devis. Exemple:

SETLOCAL ENABLEDELAYEDEXPANSION
set q=\"
child "malicious argument!q!&whoami"

Remarque SETLOCAL ENABLEDELAYEDEXPANSION semble fonctionner uniquement dans les fichiers de commandes. Pour obtenir DELAYEDEXPANSION dans une session interactive, démarrez cmd /V:ON.

Si votre fichier de commandes ne fonctionne pas avec DELAYEDEXPANSION, vous pouvez l'activer temporairement:

::region without DELAYEDEXPANSION

SETLOCAL ENABLEDELAYEDEXPANSION
::region with DELAYEDEXPANSION
set q=\"
echoarg.exe "ab !q! & echo danger"
ENDLOCAL

::region without DELAYEDEXPANSION

Si vous souhaitez transmettre du contenu dynamique à partir d'une variable contenant des guillemets échappés sous la forme "" vous pouvez remplacer "" avec \" en expansion:

SETLOCAL ENABLEDELAYEDEXPANSION
foo.exe "danger & bar=region with !dynamic_content:""=\"! & danger"
ENDLOCAL

Ce remplacement n’est pas sûr avec %...% expansion de style!

En cas de OP bash -c "g++-linux-4.1 !v_params:"=\"!" est la version sûre.


Si, pour une raison quelconque, même activer temporairement DELAYEDEXPANSION n’est pas une option, lisez ce qui suit:

En utilisant \" de dedans cmd est un peu plus sûr si on doit toujours échapper des caractères spéciaux, au lieu de juste parfois. (Il est moins probable d'oublier un signe, si c'est cohérent ...)

Pour ce faire, on fait précéder toute citation d’un signe (^"), les citations qui doivent atteindre le processus enfant en tant que littéraux doivent en outre être échappées avec un backlash (\^"). [~ # ~] tous [~ # ~] Les méta-caractères de shell doivent être échappés avec ^ ainsi, par exemple & => ^&; | => ^|; > => ^>; etc.

Exemple:

child ^"malicious argument\^"^&whoami^"

Source: Tout le monde cite les arguments de la ligne de commande dans le mauvais sens , voir "Une meilleure méthode de citation"


Pour transmettre du contenu dynamique, vous devez vous assurer que:
La partie de la commande contenant la variable doit être considérée comme "citée" par cmd.exe (Impossible si la variable peut contenir des guillemets - n’écrivez pas %var:""=\"%). Pour y parvenir, le dernier " avant la variable et le premier " après la variable ne sont pas ^-échappé. cmd-métacaractères entre ces deux " ne doit pas être échappé. Exemple:

foo.exe ^"danger ^& bar=\"region with %dynamic_content% & danger\"^"

Ce n'est pas sans danger si %dynamic_content% peut contenir des guillemets sans correspondance.

8
T S