105 votes

Échapper les guillemets doubles dans le lot script

Comment puis-je remplacer tous les guillemets dans les paramètres de mon fichier batch par des guillemets échappés ? Voici mon fichier batch 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 faire un appel à bash de Cygwin, qui exécute 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ù la première citation autour du premier chemin passé termine 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. Quelqu'un le sait-il ?

111voto

Eclipse Points 27662

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

"string with an embedded "" character"

6 votes

Doubler les citations a fait pas pour moi, mais ^ a fonctionné comme un champion.

33 votes

^ est le caractère d'échappement uniquement dans non coté dans les chaînes de caractères ; dans les chaînes de caractères à double guillemets, il est traité comme un littéral. Contrairement aux shells Unix (POSIX-like), cmd.exe n'offre AUCUNE norme coquille le traitement des guillemets doubles à l'intérieur d'une chaîne de caractères entre guillemets doubles, et L'interprétation est laissée au programme invoqué (suite dans le commentaire suivant).

12 votes

(suite du commentaire précédent) En pratique, le plus Les exécutables et les interprètes de script appliquent la convention C qui consiste à s'attendre à ce que " qui doivent être échappés en tant que \" à l'intérieur d'une chaîne de caractères doublement citée (s'applique au moins à : C/C++, Python, Perl, Ruby). En revanche, "" n'est reconnu que dans le minorité de cas : Dans les paramètres passés aux fichiers batch, "" es reconnu comme un incorporé guillemet double, mais est conservé en l'état dans les %<n> même après avoir supprimé le paramètre enfermant entre guillemets avec %~<n> . Python a gracieusement également reconnaît "" comme alternative à \" .

101voto

mklement0 Points 12597

La propre réponse de eplawless résout simplement et efficacement son problème spécifique : il remplace toutes les " dans toute la liste des arguments avec \" C'est ainsi que Bash exige que les guillemets doubles à l'intérieur d'une chaîne entre guillemets doubles soient représentés.

Pour répondre de manière générale à la question de comment échapper aux guillemets doubles à l'intérieur d'une chaîne entre guillemets doubles en utilisant cmd.exe l'interpréteur de ligne de commande de Windows (que ce soit sur la ligne de commande - souvent encore appelée à tort "invite DOS" - ou dans un fichier batch) : Voir en bas de page pour un aperçu de PowerShell .

en résumé :

La réponse dépend de le programme que vous appelez :

  • Vous doit utiliser "" lors du passage d'un argument à un (autre) fichier de lots et vous puede utiliser "" avec des applications créées avec Microsoft Compilateurs C/C++/.NET de l'UE (qui également accepter \" ), qui sous Windows inclut Python, Node.js y PowerShell (Core) 7+'s CLI ( pwsh ) mais pas l'outil de Windows PowerShell ( powershell.exe ):

    • Exemple : foo.bat "We had 3"" of rain."
  • Ce qui suit s'applique uniquement aux fichiers batch de ciblage :

    • "" est le seul moyen d'obtenir l'interpréteur de commandes ( cmd.exe ) pour traiter l'ensemble de la chaîne de caractères entre guillemets comme une chaîne de caractères de type simple (bien que cela n'ait aucune importance si vous passez simplement l'argument tous arguments par le biais de à un autre programme, avec %* )

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

      • set "str=%~1" supprime les guillemets qui l'entourent ; set "str=%str:""="%" convertit ensuite les guillemets doubles en guillemets simples.
        Veillez à utiliser les guillemets autour des parties de l'affectation afin d'éviter toute interprétation indésirable des valeurs.
  • \" es requis - comme le seulement option - par de nombreux autres programmes (par exemple, Ruby, Perl, PHP, ainsi que les programmes qui utilisent l'option CommandLineToArgv de l'API Windows pour analyser les arguments de la ligne de commande). il utilise de cmd.exe es non robustes et sûrs :

    • \" est ce que de nombreux exécutables et interprètes soit exiger - y compris Windows PowerShell - lorsqu'on leur passe des chaînes de caractères de l'extérieur sur la ligne de commande - ou, dans le cas de Les compilateurs de Microsoft, le support comme alternative à "" - en fin de compte, cependant, c'est au programme cible d'analyser la liste des arguments.
      • Exemple : foo.exe "We had 3\" of rain."
    • Cependant, l'utilisation de \" peut rupture et entraîner, au moins hypothétiquement, l'exécution indésirable et arbitraire de commandes et/ou des redirections d'entrée/sortie. :
      • Les personnages suivants présentent ce risque : & | < >
      • Par exemple, l'exemple suivant entraîne l'exécution involontaire de la commande ver Voir plus loin pour une explication et le point suivant pour une solution de contournement :
        • foo.exe "3\" of snow" "& ver."
    • Pour appeler le Windows PowerShell CLI , powershell.exe , \"" y "^"" sont robustes, mais les alternatives sont limitées (voir la section "Appeler le CLI de PowerShell ..." ci-dessous).
  • Si vous devez utiliser \" de cmd.exe il n'y a que 3 sûr les approches de cmd.exe qui sont toutefois assez lourd : Coup de chapeau à T S pour son aide.

    • En utilisant (éventuellement sélectif ) expansion variable retardée dans votre fichier batch, vous pouvez stocker le littéral \" dans un variable et faire référence à cette variable dans un "..." chaîne utilisant !var! syntaxe - voir La réponse utile de T S .

      • L'approche ci-dessus, malgré sa lourdeur, présente l'avantage de pouvoir être appliquée méthodiquement et que cela fonctionne solidement avec n'importe quelle entrée.
    • Ce n'est qu'avec les chaînes LITERALES - celles qui n'impliquent PAS de VARIABLES - que l'on obtient une approche méthodique similaire : catégoriquement ^ -évasion tous cmd.exe métacaractères : " & | < > et - si vous voulez aussi supprimer l'expansion des variables - % :
      foo.exe ^"3\^" of snow^" ^"^& ver.^"

    • Sinon, vous devez Formulez votre chaîne en reconnaissant quelles parties de la chaîne cmd.exe considère non coté en raison d'une mauvaise interprétation \" comme délimiteurs de fermeture :

      • sur littéral des portions contenant des métacaractères de l'interpréteur de commandes : ^ les effacer ; en utilisant l'exemple ci-dessus, c'est & qui doit être ^ - échappé :
        foo.exe "3\" of snow" "^& ver."

      • en portions avec %...% -références de variables de style : veiller à ce que cmd.exe les considère comme faisant partie d'un "..." chaîne de caractères y que les valeurs des variables n'ont pas elles-mêmes des guillemets intégrés et déséquilibrés - ce qui n'est même pas toujours possible .


Contexte

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

Les shells de type POSIX tels que Bash sur Systèmes de type Unix tokenise la liste d'arguments (chaîne) avant de passer les arguments individuellement au programme cible : parmi d'autres expansions, elles divisent la liste d'arguments en mots individuels (word splitting) et suppriment les caractères de citation des mots résultants (quote removal). Le programme cible est remis à un tableau de arguments individuels, verbatim c'est-à-dire avec syntaxique cotes supprimées .

En revanche, l'interpréteur de commandes de Windows n'effectue apparemment pas de tokenisation de la liste d'arguments et transmet simplement l'argument simple chaîne comprenant tous y compris les caractères de citation. - au programme cible.
Cependant, un peu de Le prétraitement a lieu avant que la chaîne unique ne soit transmise au programme cible : ^ Les caractères d'échappement en dehors des chaînes de caractères doublement citées sont supprimés (ils échappent au caractère suivant), et les références de variables (par exemple, %USERNAME% ) sont interpolé d'abord.

Ainsi, contrairement à Unix, il est de la responsabilité du programme cible d'analyser la chaîne d'arguments et de la décomposer en arguments individuels sans guillemets. Ainsi, des programmes différents peuvent exiger des méthodes d'échappement différentes y il n'y a pas un seul mécanisme d'échappement qui est garanti pour travailler avec tous les programmes - https://stackoverflow.com/a/4094897/45375 contient d'excellents renseignements sur l'anarchie que constitue l'analyse syntaxique de la ligne de commande de Windows.

En pratique, \" est très courante, mais PAS SANS danger pour cmd.exe comme indiqué ci-dessus :

Depuis cmd.exe ne reconnaît pas lui-même \" comme un s'est échappé entre guillemets, il peut mal interpréter les mots-clés ultérieurs sur la ligne de commande comme étant non coté et les interpréter potentiellement comme commandes et/ou redirections d'entrée/sortie .
En résumé, le problème apparaît si l'un des caractères suivants suit un ouverture ou déséquilibre \" : & | < > ; par exemple :

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

cmd.exe voit les jetons suivants, résultant d'une mauvaise interprétation de \" comme une double citation normale :

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

Depuis cmd.exe pense que & ver. es non coté il l'interprète comme & (l'opérateur de séquencement des commandes), suivi du nom d'une commande à exécuter ( ver. - le . est ignorée ; ver rapports cmd.exe de l'information sur la version).
L'effet global est :

  • D'abord, foo.exe est invoqué avec le premier 3 jetons uniquement.
  • Ensuite, commandez ver est exécuté.

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 passés.

De nombreux compilateurs / interprètes reconnaissent UNIQUEMENT \" - par exemple, le compilateur C/C++ de GNU, Perl, Ruby, PHP, ainsi que les programmes qui utilisent l'option CommandLineToArgv de l'API Windows pour analyser les arguments de la ligne de commande - et pour qu'ils il n'y a pas de solution simple à ce problème.
Essentiellement, vous devriez savoir à l'avance quelles parties de votre ligne de commande sont mal interprétées comme étant non citées, et sélectivement ^ -évacuer toutes les instances de & | < > dans ces parties.

En revanche, l'utilisation de "" est SAFE mais c'est Malheureusement, il n'est supporté que par les exécutables et les fichiers batch basés sur le compilateur Microsoft. (dans le cas des fichiers batch, avec les bizarreries évoquées plus haut), ce qui exclut notamment PowerShell - voir la section suivante.


Appeler le CLI de PowerShell depuis cmd.exe ou des shells de type POSIX :

Note : Voir la section inférieure pour savoir comment les citations sont traitées. à l'intérieur de PowerShell.

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

  • PowerShell [Core] v6+ reconnaît maintenant correctement "" (en plus de \" ), qui est à la fois utilisation sûre et préservation de l'espace blanc .

    • pwsh -c " ""a & c"".length " ne se casse pas et donne correctement 6
  • Windows PowerShell (l'ancienne édition dont la dernière et final est 5.1) reconnaît seulement \" o """ ce dernier étant le le choix le plus robuste de cmd.exe sous la forme "^""" (même si en interne PowerShell utilise ` comme caractère d'échappement dans les chaînes de caractères à double guillemet et accepte aussi "" - voir la section inférieure), comme nous le verrons plus loin :

Appel à Windows PowerShell de cmd.exe / un fichier batch :

  • "" rupture parce qu'elle est fondamentalement sans fondement :

    • powershell -c " ""ab c"".length " -> erreur "Il manque le terminateur dans la chaîne de caractères".
  • \" y """ travail en principe mais ne le sont pas sûr :

    • powershell -c " \"ab c\".length " fonctionne comme prévu : il produit 5 (notez le 2 espaces)
    • Mais ce n'est pas sûr, parce que cmd.exe Les métacaractères interrompent la commande, sauf s'ils sont échappés :
      powershell -c " \"a& c\".length " rupture en raison de la & qui devrait être échappé sous la forme ^&
  • \"" es sûr mais normalise les espaces blancs 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 spécifiquement où il est à la fois sûr et préserve l'espace blanc, mais avec PowerShell Core (sous Windows), c'est la même chose que \"" , c'est-à-dire, espace blanc- normalisation (comme indiqué, utilisez simplement "" là). Le mérite revient à Venryx pour avoir découvert cette approche.

    • powershell -c " "^""a& c"^"".length " travaux : ne se casse pas - malgré & - y sorties 5 c'est-à-dire les espaces blancs correctement préservés.

    • PowerShell Core : pwsh -c " "^""a& c"^"".length " travaux mais les résultats 4 c'est-à-dire normalise les espaces blancs comme \"" fait.

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

Vous doit utiliser \" qui, cependant, est à la fois sûr et préservant l'espace blanc :

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

Informations connexes

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

    • CAVEAT : Utilisation de ^ dans les paramètres passés à la call la déclaration est rompue (ceci s'applique aux deux utilisations de call : invocation d'un autre fichier batch ou binaire, et appel d'une sous-routine dans le même fichier batch) :
      • ^ instances dans double guillemet Les valeurs sont inexplicablement doublé en modifiant la valeur transmise : par exemple, si la variable %v% contient une valeur littérale a^b , call :foo "%v%" attribue "a^^b" ( !) à %1 (le premier paramètre) dans la sous-routine :foo .
      • Non cotée l'utilisation de ^ avec call es cassé en totalité en ce que ^ ne peut plus être utilisé pour échapper aux caractères spéciaux : par exemple, call foo.cmd a^&b s'interrompt discrètement (au lieu de transmettre des données littérales a&b trop foo.cmd comme ce serait le cas sans call ) - foo.cmd n'est même pas invoqué ( !), du moins sous Windows 7.
  • Echapper à un littéral % est un cas particulier malheureusement, ce qui requiert une syntaxe distincte selon qu'une chaîne de caractères est spécifiée dans le champ ligne de commande vs. dans un fichier batch ; voir https://stackoverflow.com/a/31420292/45375

    • Pour faire court : Dans un fichier batch, utilisez %% . Sur la ligne de commande, % ne peut pas être échappé, mais si vous placez une balise ^ au début, à la fin, ou à l'intérieur d'un nom de variable dans un document de type non coté (par exemple, echo %^foo% ), vous pouvez empêcher l'expansion des variables (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 ex, 100% ).
  • En général, pour travailler en toute sécurité avec des valeurs variables pouvant contenir des espaces et des caractères spéciaux :

    • Affectation : Joindre les deux le nom de la variable et la valeur dans un simple paire de guillemets ; par exemple, set "v=a & b" attribue une valeur littérale a & b à la variable %v% (par contraste, set v="a & b" ferait en sorte que les guillemets fassent partie de la valeur). Échapper au littéral % comme %% (ne fonctionne que dans les fichiers batch - voir ci-dessus).
    • Référence : Références de variables entre guillemets 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 aux impressions "a & b" (mais notez que les guillemets sont invariablement imprimés aussi). En revanche, echo %v% passe le littéral a a echo interprète & comme opérateur de séquencement des commandes, et tente donc d'exécuter une commande nommée b .
      Notez également l'avertissement ci-dessus concernant l'utilisation de ^ avec le call déclaration.
      • Externe se chargent généralement de supprimer les guillemets autour des paramètres, mais, comme indiqué, dans les fichiers de traitement par lots, vous devez le faire vous-même (par ex, %~1 pour supprimer les guillemets du 1er paramètre) et, malheureusement, il n'y a pas de moyen direct que je connaisse pour obtenir echo pour imprimer fidèlement une valeur variable sans les guillemets qui les entourent .
        • Neil offre a for -Une solution de contournement qui fonctionne tant que la valeur n'a pas de guillemets intégrés. ; par exemple :
          set "var=^&')|;,%!" for /f "delims=" %%v in ("%var%") do echo %%~v
  • cmd.exe fait pas reconnaître simple -citations comme 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 de caractères avec des espaces intégrés ; de plus, il s'ensuit que les tokens attenants aux guillemets simples et tous les tokens intermédiaires sont traités comme non quotés par cmd.exe et interprété en conséquence.

    • Cependant, étant donné que les programmes cibles effectuent en fin de compte leur propre analyse des arguments, certains programmes tels que Ruby reconnaissent les chaînes de caractères entre guillemets même sous Windows ; en revanche, les exécutables C/C++ et Perl ne reconnaissent pas les chaînes de caractères entre guillemets. pas les reconnaître.
      Cependant, même si elles sont prises en charge par le programme cible, il n'est pas conseillé d'utiliser des chaînes de caractères à guillemets simples, étant donné que leur contenu n'est pas protégé contre une interprétation potentiellement indésirable par cmd.exe .

Citation de sur PowerShell :

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

PowerShell fonctionne de manière cohérente en interne en ce qui concerne la citation :

  • à l'intérieur de chaînes de caractères entre guillemets, utilisez `" o "" pour échapper aux guillemets
  • à l'intérieur de chaînes de caractères entre guillemets, utilisez '' pour échapper aux guillemets simples

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

(Comme nous l'avons vu plus haut, transmettre un guillemet double échappé à PowerShell de l'extérieur nécessite \" ou, de manière plus robuste, \"" - rien d'autre ne fonctionne).

Malheureusement, lorsque l'on invoque externe à partir de PowerShell, vous devez tenir compte des règles de citation propres à PowerShell. y de s'échapper pour le cible programme :

  • Ce comportement problématique est également abordé et résumé dans le document suivant cette réponse ; le expérimental PSNativeCommandArgumentPassing introduite dans PowerShell Core 7.2.0-preview.5 - en supposant qu'elle devienne une fonctionnalité officielle - résoudra ce problème, du moins pour les programmes externes qui acceptent l'option \" .

Double -citations à l'intérieur double -chaînes citées :

Considérer la chaîne "3`" of rain" ce que PowerShell traduit intérieurement par le littéral 3" of rain .

Si vous voulez passer cette chaîne à un programme externe, vous devez appliquer les règles d'échappement du programme cible. en outre de PowerShell ; disons que vous voulez transmettre la chaîne de caractères à un programme C, qui s'attend à ce que les guillemets doubles intégrés soient échappés comme suit \" :

foo.exe "3\`" of rain"

Notez comment les deux `" - pour rendre PowerShell heureux - y le site \ - pour rendre le programme cible heureux - doit être présent.

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

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

En revanche, l'incorporation simple -citations dans un double -chaîne citée ne nécessite aucun échappement.

Simple -citations à l'intérieur simple -chaînes citées faire pas exiger extra s'échapper ; envisager '2'' of snow' qui est la représentation PowerShell de 2' of snow .

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

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

Cependant, double -citations à l'intérieur simple -chaînes citées qui ne nécessitent pas d'échappement pour PowerShell mais il faut encore s'échapper pour l'accès à l'UE. programme cible :

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

PowerShell v3 a introduit la magie --% option appelé le symbole d'arrêt de l'analyse ce qui soulage un peu la douleur, en passant n'importe quoi après. non interprété au programme cible, sauf pour cmd.exe -Les références à des variables d'environnement de style (par exemple, %USERNAME% ), qui sont élargi ; par exemple :

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

Notez comment l'échappement de l'élément embarqué " comme \" pour le programme cible uniquement (et non pas pour PowerShell en tant que \`" ) est suffisante.

Cependant, cette approche :

  • ne permet pas échapper à % afin d'éviter les expansions de variables d'environnement.
  • exclut direct l'utilisation de variables et d'expressions PowerShell ; au lieu de cela, la ligne de commande doit être construite dans une variable de type chaîne dans un premier temps, puis invoquée avec Invoke-Expression dans une seconde.

Un site alternative La solution de contournement* qui résout ce problème consiste à appeler via cmd /c avec un seul argument contenant le ligne de commande complète :

cmd /c "foo.exe `"3\`" of rain`" -u $env:USERNAME"

Ainsi, malgré ses nombreuses avancées, PowerShell n'a pas facilité l'échappement lors de l'appel de programmes externes - au contraire. Il a toutefois introduit la prise en charge des chaînes de caractères à guillemets simples.

Si cela ne vous dérange pas d'installer un module tiers (écrit par moi), le module Native module ( Install-Module Native ) offre une fonction d'aide compatible avec les retours en arrière et les retours en avant. ie qui rend inutile l'échappement supplémentaire et contient des adaptations importantes pour les CLI de haut niveau sous Windows :

# Simply prepend 'ie' to your external-program calls.
ie foo.exe '3" of rain' -u $env:USERNAME

0 votes

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

0 votes

Merci, @jeb, le problème n'est effectivement pas spécifique à l'utilisation de ~ - J'ai mis à jour ma réponse pour refléter ma nouvelle compréhension - veuillez commenter, si vous repérez un problème. Avez-vous une explication pour le doublement de ^ qui se produit automatiquement lorsque vous passez des paramètres à un call déclaration ?

3 votes

Je ne peux que supposer que quelqu'un chez MS a pensé que c'était brillant. Que les carets doublés seront automatiquement supprimés lors de la deuxième phase d'analyse. Mais c'était un gros échec, car cela ne fonctionne pas entre guillemets et cela empêche effectivement l'échappement de tous les caractères spéciaux. Comme call echo cat^^&dog ce n'est pas soluble avec n'importe quelle quantité de carets seuls

24voto

eplawless Points 2076

Google a fini par trouver la réponse. La syntaxe pour le remplacement des chaînes de caractères dans le langage batch est la suivante :

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

Ce qui produit "replicate me". 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 \" correctement échappé pour bash.

10voto

T S Points 863

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

Presque tous les exécutables acceptent \" en tant que fugitif " . Une utilisation sûre dans cmd n'est cependant possible qu'en utilisant DELAYEDEXPANSION.
Pour envoyer explicitement un littéral " à un processus, assigner \" à une variable d'environnement, et ensuite utiliser cette variable, chaque fois que vous avez besoin de passer une citation. Exemple :

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

Note SETLOCAL ENABLEDELAYEDEXPANSION semble ne fonctionner qu'au sein des fichiers batch. Pour obtenir DELAYEDEXPANSION dans une session interactive, lancez 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 voulez transmettre du contenu dynamique à partir d'une variable qui contient des guillemets qui sont échappés comme "" vous pouvez remplacer "" avec \" sur l'expansion :

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

Ce remplacement n'est pas sûr avec %...% l'expansion du 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 temporaire de DELAYEDEXPANSION n'est pas envisageable, lisez ce qui suit :

Utilisation de \" à partir de cmd est un peu plus sûr si l'on a toujours besoin d'échapper les caractères spéciaux, et pas seulement parfois. (Il est moins probable d'oublier un signe d'insertion, si c'est cohérent...)

Pour ce faire, on fait précéder toute citation d'un signe d'insertion ( ^" ), les guillemets qui doivent parvenir au processus fils en tant que littéraux doivent en outre être échappés avec un backlash ( \^" ). TOUTES Les métacaractères du shell doivent être échappés avec ^ également, par exemple & => ^& ; | => ^| ; > => ^> etc.

Exemple :

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

Source : Tout le monde cite les arguments de la ligne de commande de la mauvaise façon voir "Une meilleure méthode de citation".


Pour faire passer 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 "citée" par l'utilisateur. cmd.exe (Ceci est impossible si la variable peut contenir des guillemets - n'écrivez pas %var:""=\"% ). Pour ce faire, le dernier " avant la variable et le premier " après la variable ne sont pas ^ -en majuscules. cmd-metacharacteres entre ces deux " ne doit pas s'échapper. Exemple :

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

Ce n'est pas sûr, si %dynamic_content% peut contenir des guillemets non appariés.

0 votes

Compris, merci. Oui, catégoriquement ^ -scaping todo metacharacters fonctionne de manière robuste et peut être appliqué plus méthodiquement (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).

0 votes

@mklement0 Merci ! Oui, c'est vraiment pénible. C'est ennuyeux et c'est toujours trop facile d'oublier un métacaractère (c'est pourquoi j'utilise le plus souvent l'option !q! manière). Note : Votre réponse est légèrement incohérente après votre dernière modification : vers le haut, vous dites : "Est-ce que no utiliser ^" ". Plus tard, vous utiliserez ^" dans le cadre de la solution de contournement. Vous pourriez peut-être expliquer les deux méthodes ? (1) Échapper tous les métacaractères (de manière plus méthodique) / (2) Échapper de manière sélective les métacaractères dans les régions "non citées" (parfois nécessaire pour transmettre du contenu dynamique, par ex. foo.exe ^"danger ^& bar=\"%dynamic_content%\"^" - de cette façon la variable est citée pour cmd)

0 votes

Bon point, merci - réponse mise à jour. J'ai également clarifié le fait que le compilateur MS accepte les deux options \" y "" . J'ai créé un lien vers votre réponse pour l'approche plus complexe basée sur les variables. Dites-moi si cela a un sens maintenant.

0voto

Asjad Azeem Points 1

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

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X