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 :
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