Échapper des guillemets doubles dans le script de lot


91

Comment pourrais-je remplacer tous les guillemets doubles dans les paramètres de mon fichier de commandes par des guillemets doubles échappés? Ceci est mon fichier de commandes actuel, qui développe tous ses paramètres de ligne de commande à l'intérieur de 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, exécutant un compilateur croisé Linux. Malheureusement, je reçois des paramètres comme ceux-ci transmis à mon fichier de commandes:

"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 passé met fin prématurément à la chaîne passée à GCC, et passe le reste des paramètres directement à bash (ce qui échoue spectaculairement.)

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

Réponses:


103

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"

5
doubler les citations n'a pas fonctionné pour moi, mais ^ a fonctionné comme un champion.
davenpcj

25
^est le caractère d'échappement uniquement dans les chaînes sans guillemets ; dans les chaînes entre guillemets, il est traité comme un littéral. Contrairement aux shells Unix (de type POSIX), cmd.exen'offre AUCUN traitement standardisé par le shell des guillemets doubles à l'intérieur d'une chaîne entre guillemets, et l' interprétation est laissée au programme appelé (suite dans le commentaire suivant).
mklement0

9
(suite du commentaire précédent) En pratique, la plupart des exécutables / interpréteurs de script appliquent la convention C des "caractères attendus . à échapper comme \"dans une chaîne entre guillemets (s'applique au moins à: C / C ++, Python, Perl, Ruby). En revanche, ""n'est reconnu dans la minorité des cas: Dans les paramètres passés aux fichiers batch, "" est reconnu comme un intégré guillemet, mais est retenu tout comme dans le correspondant %<n>paramètre, même après le retrait des enserrant guillemets doubles avec %~<n>. Python reconnaît également gracieusement "", comme alternative à \".
mklement0

89

La propre réponse d'eplawless résout simplement et efficacement son problème spécifique: elle remplace toutes les "instances de toute la liste d'arguments par \", c'est ainsi que Bash nécessite des guillemets dans une chaîne entre guillemets pour être représentés.

Pour répondre généralement à la question de savoir comment échapper les guillemets doubles dans une chaîne entre guillemets en utilisantcmd.exe , l'interpréteur de ligne de commande Windows (que ce soit sur la ligne de commande - souvent encore appelée par erreur "l'invite DOS" - ou dans un fichier batch): Voir en bas pour un aperçu de PowerShell .

tl; dr :

  • Vous devez utiliser"" lors de la transmission d'une chaîne à un (autre) fichier de commandes et vous pouvez l' utiliser ""avec des applications créées avec les compilateurs C / C ++ / .NET de Microsoft (qui acceptent également\" ), qui sur Windows incluent Python et Node.js :

    • Exemple: foo.bat "We had 3"" of rain."

    • Ce qui suit s'applique uniquement aux fichiers de commandes:

      • ""est le seul moyen d'obtenir l'interpréteur de commande ( cmd.exe) pour traiter toute la chaîne entre guillemets comme un seul argument.

      • Malheureusement, non seulement les guillemets doubles sont conservés (comme d'habitude), mais les doubles échappés le sont aussi, donc l'obtention de la chaîne voulue est un processus en deux étapes; par exemple, en supposant que la chaîne double cité est passé comme 1er argument %1:

      • set "str=%~1"supprime les guillemets doubles; set "str=%str:""="%"convertit ensuite les guillemets doubles en simples.
        Veillez à utiliser les guillemets doubles autour des parties de l'affectation pour éviter toute interprétation indésirable des valeurs.

  • \"est requis - comme seule option - par de nombreux autres programmes (par exemple, Ruby, Perl et même Windows PowerShell de Microsoft (!)), mais SON UTILISATION N'EST PAS SÛRE :

    • \"est ce que de nombreux exécutables et interprètes ont besoin - y compris Windows PowerShell - lorsqu'ils sont passés des chaînes de l'extérieur - ou, dans le cas des compilateurs "" de Microsoft, prendre en charge comme alternative à - en fin de compte, cependant, c'est au programme cible d'analyser la liste d'arguments .
      • Exemple: foo.exe "We had 3\" of rain."
    • TOUTEFOIS, L'UTILISATION DE \"PEUT ENTRAÎNER UNE EXÉCUTION NON SOUHAITÉE ET ARBITRAIRE DE COMMANDES et / ou DES REDIRECTIONS D'ENTRÉE / SORTIE :
      • Les caractères suivants présentent ce risque: & | < >
      • Par exemple, ce qui suit entraîne une exécution involontaire de la vercommande; voir plus loin ci-dessous pour une explication et le point suivant pour une solution de contournement:
        • foo.exe "3\" of snow" "& ver."
    • Pour Windows PowerShell , \""et "^""sont des alternatives robustes, mais limitées (voir la section «Appel de la CLI de PowerShell ...» ci-dessous).
  • Si vous devez utiliser \", il n'y a que 3 approches sûres , qui sont pourtant assez lourdes : Pointe du chapeau à TS pour son aide.

    • En utilisant l' expansion de variable retardée (éventuellement sélective ) dans votre fichier de commandes, vous pouvez stocker un littéral \"dans une variable et référencer cette variable dans une "..."chaîne en utilisant la !var!syntaxe - voir la réponse utile de TS .

      • L'approche ci-dessus, bien qu'elle soit lourde, a l'avantage de pouvoir l'appliquer méthodiquement et de fonctionner de manière robuste , avec n'importe quelle entrée.
    • Seulement avec les chaînes LITTÉRALES - celles n'impliquant PAS de VARIABLES - vous obtenez une approche méthodique similaire: ^-échapper catégoriquement tous les cmd.exe métacaractères: " & | < > et - si vous voulez également supprimer l'expansion des variables - %:
      foo.exe ^"3\^" of snow^" ^"^& ver.^"

    • Sinon, vous devez formuler votre chaîne en fonction de la reconnaissance des parties de la chaîne cmd.execonsidérées comme non entre guillemets en raison d'une mauvaise interprétation en\" tant que délimiteurs de fermeture:

      • dans les portions littérales contenant des métacaractères shell: ^-scape them; en utilisant l'exemple ci-dessus, c'est &qu'il faut ^échapper:
        foo.exe "3\" of snow" "^& ver."

      • dans les portions avec %...%des références de variable -style : assurez-vous de les cmd.execonsidérer comme faisant partie d'une "..."chaîne et que les valeurs des variables n'ont pas elles-mêmes de guillemets imbriqués et déséquilibrés - ce qui n'est même pas toujours possible .

Pour plus d'informations, lisez la suite.


Contexte

Remarque: Ceci est basé sur mes propres expériences. Faites-moi savoir si je me trompe.

Les shells de type POSIX, tels que Bash sur les systèmes de type Unix, tokenisent la liste d'arguments (chaîne) avant de passer les arguments individuellement au programme cible: entre autres extensions, ils divisent la liste d'arguments en mots individuels (division des mots) et suppriment les guillemets du mots résultants (suppression des citations). Le programme cible reçoit un tableau d' arguments individuels , sans guillemets syntaxiques .

En revanche, l'interpréteur de commandes Windows ne tokenise apparemment pas la liste d'arguments et transmet simplement la chaîne unique comprenant tous les arguments - y compris les caractères entre guillemets. - au programme cible.
Cependant, un certain prétraitement a lieu avant que la chaîne unique ne soit transmise au programme cible: ^escape chars. en dehors des chaînes entre guillemets sont supprimées (elles échappent au caractère suivant), et les références de variables (par exemple, %USERNAME%) sont interpolées en premier.

Ainsi, contrairement à Unix, il est de la responsabilité du programme cible d'analyser pour analyser la chaîne d'arguments et de la décomposer en arguments individuels sans les guillemets. Ainsi, différents programmes peuvent hypothétiquement nécessiter différentes méthodes d'échappement et il n'y a pas de mécanisme d'échappement unique qui soit garanti de fonctionner avec tous les programmes - https://stackoverflow.com/a/4094897/45375 contient un excellent contexte sur l'anarchie qu'est la ligne de commande Windows analyse.

En pratique, \"c'est très courant, mais PAS SÛR , comme mentionné ci-dessus:

Puisqu'il cmd.exene reconnaît pas lui-même \"comme un guillemet double échappé , il peut mal interpréter les jetons ultérieurs sur la ligne de commande comme étant sans guillemets et potentiellement les interpréter comme des commandes et / ou des redirections d'entrée / sortie .
En résumé: les surfaces de problème, si l' un des caractères suivants suivent une ouverture ou asymétrique \" :& | < > ; par exemple:

foo.exe "3\" of snow" "& ver."

cmd.exevoit les jetons suivants, résultant d'une mauvaise interprétation \"comme un guillemet double normal:

  • "3\"
  • of
  • snow" "
  • du repos: & ver.

Puisque cmd.exepense que & ver.c'est sans guillemets , il l'interprète comme &(l'opérateur de séquencement de commandes), suivi du nom d'une commande à exécuter ( ver.- le .est ignoré; verindique cmd.exeles informations de version de).
L'effet global est:

  • Tout d'abord, foo.exeest invoqué avec les 3 premiers jetons uniquement.
  • Ensuite, la commande verest exécutée.

Même dans les cas où la commande accidentelle ne fait aucun mal, votre commande globale ne fonctionnera pas comme prévu, étant donné que tous les arguments ne lui sont pas transmis.

De nombreux compilateurs / interprètes reconnaissent UNIQUEMENT\" - par exemple, le compilateur GNU C / C ++, Python, Perl, Ruby, même Windows PowerShell de Microsoft lorsqu'il est appelé à partir de cmd.exe- et, sauf (avec des limitations) pour Windows PowerShell avec \"", pour eux, il n'y a pas de solution simple à ce problème.
Essentiellement, vous devez savoir à l'avance quelles parties de votre ligne de commande sont mal interprétées comme non ^guillemets , et échapper sélectivement à toutes les instances de & | < >dans ces parties.

En revanche, l' utilisation de ""est SÉCURISÉE , mais n'est malheureusement prise en charge que par les exécutables et les fichiers de commandes basés sur le compilateur Microsoft (dans le cas des fichiers de commandes, avec les bizarreries décrites ci-dessus), ce qui exclut notamment PowerShell - voir la section suivante.


Appel de la CLI de PowerShell à partir de cmd.exeou de shells de type POSIX:

Remarque: consultez la section inférieure pour savoir comment les citations sont gérées dans PowerShell.

Lorsqu'il est appelé de l'extérieur - par exemple, depuis cmd.exe, que ce soit à partir de la ligne de commande ou d'un fichier de commandes:

  • PowerShell [Core] v6 + reconnaît désormais correctement"" (en plus de\"), ce qui est à la fois sûr à utiliser et préservant les espaces .

    • pwsh -c " ""a & c"".length " ne casse pas et cède correctement 6
  • Windows PowerShell (l'ancienne édition dont la dernière version est 5.1) reconnaît uniquement \" et, sur Windows également """et le plus robuste \""/"^"" (même si en interne PowerShell utilise`comme caractère d'échappement dans les chaînes entre guillemets et accepte également""- voir la section du bas):

Appel de Windows PowerShell à partircmd.exe / d'un fichier de commandes:

  • "" pauses , car il n'est fondamentalement pas pris en charge:

    • powershell -c " ""ab c"".length " -> erreur "Il manque le terminateur dans la chaîne"
  • \"et """ fonctionnent en principe , mais ne sont pas sûrs :

    • powershell -c " \"ab c\".length "fonctionne comme prévu: il sort 5(notez les 2 espaces)
    • Mais ce n'est pas sûr, car les cmd.exemétacaractères cassent la commande, à moins d'être échappés:
      powershell -c " \"a& c\".length " breaks , en raison de &, qui devraient être échappés comme^&
  • \""est sûr , mais normalise les espaces intérieurs , ce qui peut être indésirable:

    • powershell -c " \""a& c\"".length "sorties 4(!), car les 2 espaces sont normalisés à 1.
  • "^""est le meilleur choix pour Windows PowerShell en particulier , où il est à la fois sûr et préservant les espaces, mais avec PowerShell Core (sous Windows), c'est la même chose que la \""normalisation des espaces . Le mérite revient à Venryx d' avoir découvert cette approche.

    • powershell -c " "^""a& c"^"".length " fonctionne : ne casse pas - malgré &- et les sorties 5, c'est à dire, des espaces correctement préservés.

    • PowerShell Core : pwsh -c " "^""a& c"^"".length " fonctionne , mais produit 4, c'est-à-dire normalise les espaces , comme le \""fait.

Sur les plates-formes de type Unix (Linux, macOS), lors de l'appel de la CLI de PowerShell [Core] ,, à pwshpartir d'un shell de type POSIX tel que bash:

Vous devez utiliser\" , qui, cependant, est à la fois sûr et préservant les espaces :

$ pwsh -c " \"a&  c|\".length" # OK: 5

Informations connexes

  • ^ne peut être utilisé comme caractère d'échappement en non cotées chaînes - à l' intérieur des chaînes entre guillemets, ^n'est pas spécial et traité comme un littéral.

    • CAVEAT : l' utilisation des ^paramètres in passés à l' callinstruction est interrompue (cela s'applique aux deux utilisations de call: l'appel d'un autre fichier de commandes ou binaire, et l'appel d'un sous-programme dans le même fichier de commandes):
      • ^les instances dans les valeurs entre guillemets sont inexplicablement doublées , modifiant la valeur transmise: par exemple, si la variable %v%contient une valeur littérale a^b, call :foo "%v%"assigne "a^^b"(!) à %1(le premier paramètre) dans le sous-programme :foo.
      • L' utilisation sans guillemets de ^with callest complètement interrompue dans la mesure où elle ^ne peut plus être utilisée pour échapper des caractères spéciaux : par exemple, descall foo.cmd a^&binterruptions silencieuses (au lieu de passera&baussi deslittérauxfoo.cmd, comme ce serait le cas sanscall) -foo.cmdn'est même jamais invoquée (!), Du moins sous Windows 7.
  • Échapper un littéral %est un cas spécial , malheureusement, qui nécessite une syntaxe distincte selon qu'une chaîne est spécifiée sur la ligne de commande ou dans un fichier de commandes ; voir https://stackoverflow.com/a/31420292/45375

    • En bref: dans un fichier batch, utilisez %%. Sur la ligne de commande, %ne peut pas être échappé, mais si vous placez un ^au début, à la fin ou à l'intérieur d'un nom de variable dans une chaîne sans guillemets (par exemple, echo %^foo%), vous pouvez empêcher l'expansion de la variable (interpolation); %les instances de la ligne de commande qui ne font pas partie d'une référence de variable sont traitées comme des littéraux (par exemple, 100%).
  • En règle générale, pour travailler en toute sécurité avec des valeurs variables pouvant contenir des espaces et des caractères spéciaux :

    • Affectation : placez à la fois le nom de la variable et la valeur dans une seule paire de guillemets doubles ; par exemple, set "v=a & b"assigne une valeur littérale a & bà la variable %v%(en revanche, set v="a & b"ferait partie des guillemets doubles de la valeur). Échapper les %instances littérales comme %%(fonctionne uniquement dans les fichiers batch - voir ci-dessus).
    • Référence : Double-quote des références de variable pour s'assurer que leur valeur n'est pas interpolée; par exemple, echo "%v%"ne soumet pas la valeur de %v%à l'interpolation et à l'impression "a & b"(mais notez que les guillemets sont invariablement imprimés également). En revanche, echo %v%passe littéral aà echo, interprète &comme l'opérateur de séquencement de commandes, et tente donc d'exécuter une commande nommée b.
      Notez également la mise en garde ci-dessus concernant l'utilisation de ^avec la calldéclaration.
    • Les programmes externes prennent généralement soin de supprimer les guillemets doubles entourant les paramètres, mais, comme indiqué, dans les fichiers batch, vous devez le faire vous-même (par exemple, %~1pour supprimer les guillemets doubles englobants du premier paramètre) et, malheureusement, il n'y a pas façon que je connais pour arriver echoà imprimer une valeur variable fidèlement sans les guillemets doubles .
      • Neil propose une forsolution de contournement qui fonctionne tant que la valeur n'a pas de guillemets doubles incorporés ; par exemple:
        set "var=^&')|;,%!" for /f "delims=" %%v in ("%var%") do echo %%~v
  • cmd.exene reconnaît pas les guillemets simples comme des délimiteurs de chaîne - ils sont traités comme des littéraux et ne peuvent généralement pas être utilisés pour délimiter des chaînes avec des espaces incorporés; aussi, il s'ensuit que les jetons accolés aux guillemets simples et tous les jetons intermédiaires sont traités comme non entre guillemets cmd.exeet interprétés en conséquence.

    • Cependant, étant donné que les programmes cibles effectuent finalement leur propre analyse des arguments, certains programmes tels que Ruby reconnaissent les chaînes entre guillemets même sous Windows; en revanche, les executables de C / C, Perl et Python ne pas les reconnaître.
      Même s'il est pris en charge par le programme cible, cependant, il n'est pas conseillé d'utiliser des chaînes entre guillemets simples, étant donné que leur contenu n'est pas protégé contre une interprétation potentiellement indésirable par cmd.exe.

Je cite à l' intérieur PowerShell:

Windows PowerShell est un shell beaucoup plus avancé que cmd.exe, et il fait partie de Windows depuis de nombreuses années maintenant (et PowerShell Core a également apporté l'expérience PowerShell à macOS et Linux).

PowerShell fonctionne de manière cohérente en interne en ce qui concerne les citations:

  • dans des chaînes entre guillemets, utilisez `"ou ""pour échapper des guillemets
  • dans des chaînes entre guillemets simples, utilisez ''pour échapper les guillemets simples

Cela fonctionne sur la ligne de commande PowerShell et lors du passage de paramètres aux scripts ou fonctions PowerShell à partir de PowerShell.

(Comme indiqué ci-dessus, transmettre un guillemet double échappé à PowerShell de l'extérieur nécessite \"ou, plus robuste, \""rien d'autre ne fonctionne).

Malheureusement, lorsque vous appelez des programmes externes à partir de PowerShell, vous êtes confronté à la nécessité d'adapter à la fois les règles de citation de PowerShell et de s'échapper pour le programme cible :

Ce comportement problématique est également discuté et résumé dans cette réponse

Double -quotes intérieur doubles cordes -quoted :

Considérez string "3`" of rain", que PowerShell traduit en interne en littéral 3" of rain.

Si vous souhaitez transmettre cette chaîne à un programme externe, vous devez appliquer l'échappement du programme cible en plus de celui de PowerShell ; disons que vous voulez passer la chaîne à un programme C, qui s'attend à ce que les guillemets incorporés soient échappés comme \":

foo.exe "3\`" of rain"

Notez comment les deux `" - pour rendre PowerShell heureux - et le \- pour rendre le programme cible heureux - doivent être présents.

La même logique s'applique à l'appel d'un fichier de commandes, où ""doit être utilisé:

foo.bat "3`"`" of rain"

En revanche, l'incorporation de guillemets simples dans une chaîne entre guillemets doubles ne nécessite aucun échappement.

Simple -quotes intérieur simples chaînes -quoted ne pas besoin supplémentaire échapper; consider'2'' of snow', qui est la représentation de PowerShell2' of snow.

foo.exe '2'' of snow'
foo.bat '2'' of snow'

PowerShell convertit les chaînes entre guillemets simples en chaînes entre guillemets avant de les transmettre au programme cible.

Cependant, doubles -quotes intérieur simples cordes -quoted , qui ne nécessitent pas de s'échapper PowerShell , ne doivent encore être échappé pour le programme cible :

foo.exe '3\" of rain'
foo.bat '3"" of rain'

PowerShell v3 a introduit l' --%option magique , appelée symbole d'arrêt de l'analyse , qui atténue une partie de la douleur, en transmettant tout ce qui n'a pas été interprété au programme cible, sauf pour cmd.exeles références de variable d'environnement -style (par exemple, %USERNAME%), qui sont développées; par exemple:

foo.exe --% "3\" of rain" -u %USERNAME%

Notez comment l'échappement de l'incorporé "comme \"pour le programme cible uniquement (et pas aussi pour PowerShell as \`") est suffisant.

Cependant, cette approche:

  • n'autorise pas les caractères d' échappement % afin d'éviter les extensions de variables d'environnement.
  • empêche l' utilisation directe des variables et expressions PowerShell; au lieu de cela, la ligne de commande doit être construite dans une variable chaîne dans un premier temps, puis appelée avec Invoke-Expressiondans une seconde.

Ainsi, malgré ses nombreuses avancées, PowerShell n'a pas beaucoup facilité l'évasion lors de l'appel de programmes externes. Il a toutefois introduit la prise en charge des chaînes entre guillemets simples.

Je me demande s'il est fondamentalement possible dans le monde Windows de passer au modèle Unix de laisser le shell faire toute la tokenisation et la suppression des citations de manière prévisible , dès le départ , quel que soit le programme cible , puis appeler le programme cible en transmettant les jetons résultants .


Belle description! Mais ... Literal use of ^ in double-quoted strings can, be problematic when applying ~ ...pas vraiment. Le tilde supprime uniquement les guillemets externes lorsqu'ils sont présents. La perte de tapis est un problème de manipulation elle-même. Normalement, un set "param=%~1"résout ce problème.
jeb

Merci, @jeb, le problème n'est en effet pas spécifique à l'utilisation de ~- j'ai mis à jour ma réponse pour refléter ma nouvelle compréhension - s'il vous plaît commenter, si vous repérez un problème. Avez-vous une explication pour le doublement de ce ^qui se produit automatiquement lorsque vous passez des paramètres à une callinstruction?
mklement0

3
Je ne peux que deviner que quelqu'un de MS a pensé que c'était génial. Que les carets doublés seront automatiquement supprimés lors de la deuxième phase d'analyse. Mais cela a été un gros échec, car cela ne fonctionne pas entre guillemets et empêche efficacement l'échappement de caractères spéciaux. Comme si call echo cat^^&dogce n'était pas résoluble avec une quantité de caractères seulement
jeb

Merci, @jeb, je n'avais même pas envisagé l' utilisation non citée de ^with call, qui, comme vous le faites remarquer, est gravement cassée. Il semble que dans call echo cat^&dog(single ^qui échappe correctement le &) la commande cible ( echo) n'est même jamais invoquée (!) - la commande entière échoue silencieusement. J'ai mis à jour la réponse en conséquence.
mklement0

Bonne réponse. Cependant, je ne recommanderais pas ""comme échappé "mais toujours \"(voir ma réponse pour une manière moins dangereuse de l'utiliser à partir de cmd). Je ne sais pas tout document officiel qui définit ""comme une citation échappé, mais au moins 2 qui mentionnent \": .NET et VS . Bien que mal documenté, l' API Win32 suit également ces règles.
TS

23

Google a finalement trouvé la réponse. La syntaxe pour le remplacement de chaîne dans le lot 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%"

Ce qui remplace toutes les instances de "with \", correctement échappées pour bash.


9

En complément de l'excellente réponse de mklement0 :

Presque tous les exécutables acceptent \"comme échappés ". Cependant, une utilisation sûre dans cmd n'est presque possible qu'en utilisant DELAYEDEXPANSION.
Pour envoyer explicitement un littéral "à un processus, attribuez- \"lui une variable d'environnement, puis utilisez cette variable chaque fois que vous devez passer un devis. Exemple:

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

Remarque SETLOCAL ENABLEDELAYEDEXPANSIONsemble fonctionner uniquement dans les fichiers batch. Pour obtenir DELAYEDEXPANSION dans une session interactive, démarrez cmd /V:ON.

Si votre fichier batch 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 comme "" vous pouvez le remplacer ""par \"lors de l'expansion:

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

Ce remplacement n'est pas sûr avec l' %...%extension de style!

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


Si, pour une raison quelconque, l'activation même temporaire de DELAYEDEXPANSION n'est pas une option, lisez la suite:

Utiliser \"depuis cmd est un peu plus sûr si l'on a toujours besoin d'échapper aux caractères spéciaux, plutôt que parfois. (Il est moins probable d'oublier un signe d'insertion, s'il est cohérent ...)

Pour ce faire, on fait précéder les guillemets d'un signe caret ( ^"), les guillemets qui doivent atteindre le processus enfant en tant que littéraux doivent en plus être échappés avec un backlash ( \^"). TOUS les méta-caractères du shell doivent également être échappés avec ^, 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, il faut s'assurer de ce qui suit:
La partie de la commande qui contient la variable doit être considérée comme "entre guillemets" par cmd.exe(Ceci est impossible si la variable peut contenir des guillemets - ne pas écrire%var:""=\"% ). Pour ce faire, le dernier "avant la variable et le premier "après la variable ne sont pas ^échappés. Les métacaractères cmd entre ces deux "ne doivent pas être échappés. Exemple:

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

Ce n'est pas sûr, si %dynamic_content%peut contenir des citations sans correspondance.


Compris, merci. Oui, ^échapper catégoriquement à tous les métacaractères fonctionne de manière robuste et peut être appliqué de manière plus méthodique (mais c'est évidemment une douleur royale dans la partie du corps de votre choix). J'ai mis à jour ma réponse en conséquence (et je vous ai donné du crédit).
mklement0

@ mklement0 Merci! Oui, c'est vraiment une douleur. C'est ennuyeux et c'est encore trop facile d'oublier un métacaractère (donc j'utilise surtout le !q!chemin). Remarque: Votre réponse est légèrement incohérente après votre dernière modification: vers le haut, vous dites: "Ne pas utiliser ^"". Plus tard, vous utilisez ^"dans le cadre de la solution de contournement. Peut-être pourriez-vous expliquer les deux manières? (1) Échappement de tous les métacaractères (plus méthodiquement) / (2) Échappement sélectif des métacaractères dans les régions "sans guillemets" (parfois nécessaire pour transmettre du contenu dynamique, par exemple foo.exe ^"danger ^& bar=\"%dynamic_content%\"^"- de cette façon la variable est citée pour cmd)
TS

Bon point, merci - réponse mise à jour. J'ai également précisé que le compilateur MS accepte à la fois \"et "". J'ai lié à votre réponse pour l'approche à base de variables plus impliquée. Faites-moi savoir si cela a du sens maintenant.
mklement0

1
@ mklement0 Votre réponse avait toujours du sens :-) Je voulais juste donner quelques idées d'améliorations possibles. J'ai également ajouté l'exemple à propos de %dynamic_content%dans ma réponse. Pensez-vous qu'il est suffisamment détaillé ou dois-je en expliquer davantage?
TS

3
Cool, merci de me l'avoir fait savoir. Bonne idée de localiser le setlocal delayedexpansion, mais vous devez terminer le bloc avec endlocal(sans argument). Honnêtement, ma tête a commencé à tourner en regardant votre Gist. Nous avons vraiment affaire à des cas extrêmes ici, et je pense que les futurs lecteurs trouveront tout ce dont ils ont besoin entre nos deux réponses.
mklement0

0

Si la chaîne est déjà entre guillemets, utilisez un autre guillemet pour annuler son action.

echo "Insert tablename(col1) Values('""val1""')" 

-3

Par exemple, pour l'outil Unreal Engine Automation exécuté à partir d'un fichier de commandes - cela a fonctionné pour moi

par exemple: -cmdline = "-Messaging" -device = device -addcmdline = "- SessionId = session -SessionOwner = 'owner' -SessionName = 'Build' -dataProviderMode = local -LogCmds = 'LogCommodity OFF' -execcmds = 'liste d'automatisation ; runtests tests + séparés + par + T1 + T2; quitter '"-run

J'espère que cela aide quelqu'un, a travaillé pour moi.


Essayez de distiller le concept que vous avez appris que vous essayez de partager dans un exemple clair, plutôt que dans un long copier-coller presque non pertinent de votre travail.
run_the_race
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.