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 :
\"
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
ver
commande; 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.exe
considé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.exe
considé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.exe
ne 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.exe
voit les jetons suivants, résultant d'une mauvaise interprétation \"
comme un guillemet double normal:
"3\"
of
snow" "
- du repos:
& ver.
Puisque cmd.exe
pense 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é; ver
indique cmd.exe
les informations de version de).
L'effet global est:
- Tout d'abord,
foo.exe
est invoqué avec les 3 premiers jetons uniquement.
- Ensuite, la commande
ver
est 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.exe
ou 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.exe
mé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] ,, à pwsh
partir 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' call
instruction 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 call
est 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^&b
interruptions silencieuses (au lieu de passera&b
aussi deslittérauxfoo.cmd
, comme ce serait le cas sanscall
) -foo.cmd
n'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 call
dé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,
%~1
pour 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
for
solution 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.exe
ne 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.exe
et 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.exe
les 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-Expression
dans 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 .