Échapper guillemets doubles dans Script lot
-
05-09-2019 - |
Question
Comment pourrais-je aller à remplacer tous les guillemets doubles dans les paramètres de mon fichier de commandes avec des guillemets doubles échappées? Ceci est mon fichier de commandes en cours, qui se développe à l'intérieur de la chaîne tous ses paramètres de ligne de commande:
@echo off
call bash --verbose -c "g++-linux-4.1 %*"
Il utilise ensuite cette chaîne pour faire un appel à bash Cygwin, l'exécution d'un compilateur croisé Linux. Malheureusement, je reçois des paramètres tels que ceux-ci passé à 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"
Lorsque la première citation dans le premier trajet est passé en terminant prématurément la chaîne étant transmis à GCC, et en passant le reste des paramètres directement à bash (qui échoue spectaculairement.)
J'imagine si je peux concaténer les paramètres en une seule chaîne échapper alors les guillemets il devrait fonctionner correctement, mais je vais avoir du mal à déterminer comment faire cela. Est-ce que quelqu'un sait?
La solution 3
Google a fini avec la réponse. La syntaxe de remplacement de chaîne en lots est la suivante:
set v_myvar=replace me
set v_myvar=%v_myvar:ace=icate%
Ce qui produit "me répliquer". Mon script ressemble maintenant à ceci:
@echo off
set v_params=%*
set v_params=%v_params:"=\"%
call bash -c "g++-linux-4.1 %v_params%"
remplace toutes les instances de "
avec \"
, correctement saisies pour bash.
Autres conseils
Le caractère d'échappement dans les scripts de traitement par lots est ^
. Mais pour les chaînes entre guillemets doubles, doubler les guillemets:
"string with an embedded "" character"
eplawless propre réponse simple et résout efficacement son problème spécifique: il remplace toutes les instances de "
dans la liste des arguments avec toute \"
, ce qui est la façon dont Bash nécessite des guillemets doubles, une chaîne double cité à représenter.
Pour répondre de façon générale la question de comment échapper les guillemets doubles, une chaîne double entre guillemets cmd.exe
, l'interpréteur de ligne de commande de Windows (que ce soit sur la ligne de commande - souvent encore, à tort appelé " DOS invite » - ou dans un fichier batch): Voir en bas pour un look à PowerShell
tl; dr :
-
doit utiliser
""
lors du passage d'une chaîne à un (autre) fichier batch vous peut utiliser""
avec les applications créées avec Microsoft 's C / C ++ /. compilateurs NET (qui aussi accepter\"
), qui sous Windows comprend Python et Node.js :-
Exemple:
foo.bat "We had 3"" of rain."
-
Concerne les fichiers batch seulement:
-
""
est le seul moyen d'obtenir l'interpréteur de commande (cmd.exe
) pour traiter toute la chaîne entre guillemets comme à argument. -
Malheureusement, cependant, ne sont pas seulement les guillemets doubles entourant répartis (comme d'habitude), mais si on les échappées doublé, pour obtenir ainsi la chaîne de caractères prévue 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 enserrant;set "str=%str:""="%"
convertit ensuite les guillemets doubles à ceux doublé simples.
Assurez-vous d'utiliser les guillemets doubles enserrant autour des pièces d'affectation afin d'éviter une interprétation non désirée des valeurs.
-
-
-
\"
est requis - comme la seule option - par de nombreux autres programmes , (Eg, Ruby, Perl, et même propre PowerShell de Microsoft ()) , mais UTILISATION EST DANGEREUX :-
\"
est ce que beaucoup de executables et d'interprètes soit exigent - y compris le propre PowerShell de Microsoft lorsque les chaînes passent de l'extérieur - ou, dans le cas de compilateurs Microsoft, soutien comme une alternative à""
-. en fin de compte, cependant, il est au programme cible pour analyser la liste des arguments- Exemple:
foo.exe "We had 3\" of rain."
- Exemple:
- CEPENDANT, UTILISATION DE
\"
PEUT PROVOQUER INDÉSIRABLES, ARBITRAIRE EXECUTION DES ORDRES et / ou Redirections ENTRÉE / SORTIE :- Les caractères suivants présentent ce risque:
& | < >
- Par exemple, les résultats suivants dans 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."
-
- Les caractères suivants présentent ce risque:
- Pour PowerShell sur de Windows ,
\""
et"^""
sont des alternatives robustes, mais limitées (voir la section "Appel CLI PowerShell ..." ci-dessous ).
-
-
Si vous devez utiliser
\"
, il y a seulement 3 sécurité approches , qui sont cependant assez lourd : Astuce du chapeau TS pour son aide.-
Utilisation (peut-être sélectif ) a retardé l'expansion variable dans votre fichier de commandes, vous pouvez magasin
\"
littéral dans une variable et référence variable dans une chaîne de"..."
en utilisant la syntaxe!var!
- voir T S .- L'approche ci-dessus, en dépit d'être lourde, a l'avantage que vous pouvez l'appliquer méthodiquement et que cela fonctionne avec vigueur , avec une entrée.
-
uniquement avec des chaînes littérales - ceux ne comportant PAS VARIABLES - obtenez-vous une approche tout aussi méthodique: catégorique
^
-évasion touscmd.exe
métacaractères:" & | < >
et - si vous voulez aussi supprimer l'extension de variable -%
:
foo.exe ^"3\^" of snow^" ^"^& ver.^"
-
Dans le cas contraire, vous devez formuler votre chaîne fondée sur la reconnaissance que des parties de la
cmd.exe
chaîne considère unquoted en raison de mal interpréter\"
comme délimiteurs de fermeture:-
en littéral portions contenant des métacaractères du shell: les
^
-fuite; en utilisant l'exemple ci-dessus, il est&
qui doit être^
-échappé:
foo.exe "3\" of snow" "^& ver."
-
dans les parties avec des références variables de style
%...%
: veiller à ce quecmd.exe
les considère comme faisant partie d'une chaîne de"..."
et qui que les valeurs des variables ne le font pas eux-mêmes ont intégré , citations asymétriques -. qui est même pas toujours possible
-
-
Pour plus d'information, lisez la suite.
Historique
Note: Ceci est basé sur mes propres expériences. Ne laissez-moi savoir si je me trompe.
Shells POSIX comme tels que Bash sur le programme cible systèmes Unix tokenize la liste des arguments (chaîne) avant la transmission d'arguments individuellement : entre autres extensions, ils diviser la liste des arguments en mots individuels (séparation de mots) et supprimer les caractères citant des mots résultant (citation suppression). Le programme cible est remis un array de arguments individuels , avec des guillemets syntaxiques supprimés .
En revanche, l'interpréteur de commandes de Windows ne tokenize apparemment pas la liste des arguments et passe simplement le à chaîne comprenant tous arguments - y compris les caractères citant. -. Au programme cible
Cependant, certains pré-traitement a lieu avant la chaîne unique est transmise au programme cible: ^
échapper à caractères. en dehors des chaînes entre guillemets sont enlevés (ils échappent à l'omble chevalier suivant.) et des références variables (par exemple, %USERNAME%
) sont interpolée premier.
Ainsi, contrairement à Unix, il est de la responsabilité du programme cible pour analyser pour analyser la chaîne d'arguments et de le décomposer en arguments individuels avec des guillemets supprimés. Ainsi, les programmes différents peuvent nécessiter hypothétiquement différentes méthodes qui s'échappent et il n'y a pas un seul mécanisme d'échappement qui est garantie pour travailler avec tous les programmes - < a href = « https://stackoverflow.com/a/4094897/45375 »> https://stackoverflow.com/a/4094897/45375 contient un excellent fond sur l'anarchie qui est l'analyse syntaxique ligne de commande Windows.
Dans la pratique, \"
est très fréquent, mais pas SÛR , comme mentionné ci-dessus:
Depuis cmd.exe
lui-même ne reconnaît pas \"
comme se sont échappés guillemet, il peut mal interpréter plus tard jetons sur la ligne de commande comme unquoted et potentiellement les interpréter comme commandes et / ou entrée / sortie redirections .
En résumé: les surfaces de problème, si l'un des caractères suivants suivent un ouverture ou asymétrique \"
: & | < >
; par exemple:
foo.exe "3\" of snow" "& ver."
cmd.exe
voit les jetons suivants, résultant de mauvaise interprétation\"
comme guillemet régulier:
-
"3\"
-
of
-
snow" "
- repos:
& ver.
Depuis cmd.exe
pense que & ver.
est non cotées , il l'interprète comme &
(l'opérateur commande le séquençage), suivi du nom d'une commande à exécuter (ver.
- le .
est ignoré, les rapports de ver
informations sur la version de cmd.exe
).
L'effet global est:
- Tout d'abord,
foo.exe
est invoqué avec le premier 3 jetons seulement. - Ensuite, la commande est exécutée
ver
.
Même dans les cas où la commande accidentelle ne fait pas de mal, votre commande globale ne fonctionnera pas comme prévu, étant donné que tous les arguments sont transmis.
De nombreux compilateurs / interprètes ne reconnaissent que \"
- par exemple, la GNU C / C ++, Python, Perl, Ruby, même propre PowerShell appelé à partir de Microsoft cmd.exe
- et, à l'exception de PowerShell avec \""
, pour eux il n'y a pas de solution simple à ce problème.
Essentiellement, vous auriez à savoir à l'avance quelles parties de votre ligne de commande sont mal interprétés comme non cotés, et ^
-s'échapper de manière sélective toutes les instances de & | < >
dans ces parties.
En revanche, utilisation de ""
est SÛR , mais est malheureusement pris en charge uniquement par executables base compilateur Microsoft et les fichiers batch (dans le cas des fichiers de traitement par lots, avec les bizarreries ci-dessus), discuté qui exclut notables PowerShell -. voir la section suivante
Appel de CLI de PowerShell à partir de coquilles de cmd.exe
ou comme POSIX:
Note: Voir la section inférieure de la façon dont est traitée citant le dans PowerShell
. PowerShell , lorsqu'il est appelé de l'extérieur - par exemple, de cmd.exe
, que ce soit à partir de la ligne de commande ou d'un fichier batch - reconnaît uniquement \"
et, sous Windows également """
et \""
plus robuste / "^""
(même si interne PowerShell utilise `
comme le caractère d'échappement dans les chaînes entre guillemets doubles et accepte également ""
- voir en bas section):
de Windows , appelant cmd.exe
/ un fichier batch:
-
""
pauses , car il est fondamentalement non pris en charge:-
powershell -c " ""ab c"".length "
-> erreur "La chaîne est manquante la terminaison"
-
-
\"
et"""
travail , en principe, , mais ne sont pas sécurité :-
powershell -c " \"ab c\".length "
fonctionne comme prévu: il émet5
(note 2 espaces) - Mais ce n'est pas sûr, parce que
cmd.exe
métacaractères briser la commande, à moins que se sont échappés:
powershell -c " \"a& c\".length "
pauses , en raison de la&
, qui devrait être échappé comme^&
-
-
\""
est sécurité , mais normaliser l'intérieur des espaces , qui peut être non souhaité:- sorties
powershell -c " \""a& c\"".length "
4
(!), Parce que les 2 espaces sont normalisés à 1.
- sorties
-
"^""
est le meilleur choix pour Windows PowerShell spécifiquement , où il est à la fois sécuritaire et la préservation des espaces, mais avec PowerShell de base (sous Windows), il est le même que\""
, c.-à-whitespace- normalisant . Le crédit va à Venryx pour découvrir cette approche.-
powershell -c " "^""a& c"^"".length "
fonctionne :. ne pas casser - malgré&
- et sorties5
, à savoir, les espaces correctement conservés -
PowerShell Tore :
<. / li>pwsh -c " "^""a& c"^"".length "
fonctionne , mais les sorties4
, ie normalise les espaces , comme\""
fait
-
les plates-formes Unix-like (Linux, Mac OS), appelant PowerShell Tore CLI de, pwsh
à partir d'une coquille Posix telle comme bash
:
doit utiliser \"
, qui est cependant à la fois sûr et des espaces préservant :
$ pwsh -c " \"a& c|\".length" # OK: 5
Informations connexes
-
^
ne peut être utilisé comme caractère d'échappement dans unquoted cordes - à l'intérieur des chaînes entre guillemets doubles,^
n'est pas spécial et traité comme un littéral <. / p>- CAVEAT : Utilisation des
^
des paramètres passés à l'instructioncall
est cassé ( cela pour les deux utilisations decall
: invoquer un autre fichier batch ou binaire, et appeler un sous-programme dans le même fichier batch):- les instances de
^
dans double cité Les valeurs sont inexplicablement doublé , la modification de la valeur transmise: par exemple, si%v%
variable contient la valeur littéralea^b
,call :foo "%v%"
attribue"a^^b"
(!) à%1
(le premier paramètre) dans sous-programme:foo
. - non cotées utilisation de
^
aveccall
est rompu tout à fait dans ce^
ne peut plus être utilisé pour échapper à des caractères spéciaux : par exemple,call foo.cmd a^&b
tranquillement (pauses au lieu de passer trop littéralea&b
foo.cmd
, comme ce serait le cas sanscall
) - (!).foo.cmd
est jamais invoqué, au moins sur Windows 7
- les instances de
- CAVEAT : Utilisation des
-
Échapper une
%
littérale est un cas particulier , malheureusement, qui nécessite une syntaxe distincte en fonction de si une chaîne est spécifiée sur la ligne de commande vs . dans un fichier batch ; voir https://stackoverflow.com/a/31420292/45375- Le court de lui: l'intérieur d'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 unquoted string (par exemple,echo %^foo%
), vous pouvez empêcher l'expansion variable ( interpolation); instances de%
sur la ligne de commande qui ne font pas partie d'une référence variable sont traités comme des littéraux (par exemple,100%
).
- Le court de lui: l'intérieur d'un fichier batch, utilisez
-
En général, pour travailler en toute sécurité avec des valeurs variables qui peuvent contenir des espaces et des caractères spéciaux :
- Affectation : Enclose à la fois nom de variable et la valeur dans une à paire de guillemets doubles ; par exemple, attribue
set "v=a & b"
valeur littéralea & b
à%v%
variable (en revanche,set v="a & b"
rendrait la partie de la valeur des guillemets doubles). Échapper à des instances de%
littéral comme%%
. (Ne fonctionne que dans des fichiers batch - voir ci-dessus) - Référence : références guillemet variables pour que leur valeur n'est pas interpolé; par exemple,
echo "%v%"
ne soumet pas la valeur de%v%
à interpolation et impressions"a & b"
(mais notez que les guillemets sont toujours imprimés aussi). En revanche,echo %v%
passea
littéraleecho
, interprète&
comme l'opérateur commande le séquençage, et tente donc d'exécuter une commande nomméeb
.
A noter également la mise en garde ci-dessus concernant l'utilisation de^
avec l'instructioncall
. - externe programmes prennent généralement soin de supprimer enfermant des guillemets doubles autour de paramètres, mais, comme il est indiqué, dans des fichiers batch que vous devez faire vous-même (par exemple,
%~1
pour enlever enfermer les guillemets doubles de la 1er paramètre) et, malheureusement, il n'y a aucun moyen direct que je connaisse pour obtenirecho
d'imprimer une valeur variable fidèlement sans les guillemets enserrant .
- Affectation : Enclose à la fois nom de variable et la valeur dans une à paire de guillemets doubles ; par exemple, attribue
-
cmd.exe
fait pas reconnaître à -quotes comme chaîne délimiteurs - ils sont traités comme littéraux et ne peuvent généralement pas être utilisés pour délimiter chaînes avec des espaces intégrés; En outre, il en résulte que les jetons en butée contre la guillemets simples et des jetons entre les deux sont considérés comme non cotés parcmd.exe
et interprétés en conséquence.- Toutefois, étant donné que les programmes cibles réalisent finalement leur propre analyse des arguments, certains programmes tels que Ruby reconnaissent les chaînes entre guillemets simples, même sous Windows; en revanche, les executables de C / C, Perl et Python font pas les reconnaître.
Même si elle est soutenue par le programme cible, cependant, il est conseillé d'utiliser des guillemets simples chaînes, étant donné que leur contenu ne sont pas protégés contre l'interprétation potentiellement indésirables parcmd.exe
.
- Toutefois, étant donné que les programmes cibles réalisent finalement leur propre analyse des arguments, certains programmes tels que Ruby reconnaissent les chaînes entre guillemets simples, même sous Windows; en revanche, les executables de C / C, Perl et Python font pas les reconnaître.
Je cite dans les PowerShell:
Windows PowerShell est un shell beaucoup plus avancé que cmd.exe
, et il a fait partie de Windows depuis de nombreuses années (et PowerShell de base a l'expérience PowerShell pour MacOS et Linux ainsi).
fonctionne PowerShell toujours interne par rapport à citer:
- à l'intérieur des chaînes entre guillemets doubles, utilisez
`"
ou""
pour échapper à des guillemets doubles - dans les chaînes entre guillemets simples, utilisez
''
pour échapper à guillemets simples
Cela fonctionne sur la ligne de commande PowerShell et passer des paramètres aux scripts PowerShell ou fonctions de dans les PowerShell.
(Comme indiqué plus haut, le passage d'un guillemet échappé à PowerShell de l'extérieur nécessite \"
ou, plus robuste, \""
- rien ne fonctionne autrement).
Malheureusement, lors de l'appel externes programmes de PowerShell, vous êtes confrontés à la nécessité à la fois adapter propres règles de cotation de PowerShell et pour échapper à la cible programme:
Ce comportement problématique est également discuté et résumées dans cette GitHub docs question
Double -quotes intérieur doubles chaînes -quoted :
Considérez chaîne "3`" of rain"
, qui PowerShell interne se traduit par 3" of rain
littérale.
Si vous voulez transmettre cette chaîne à un programme externe, vous devez appliquer le programme de cible échapper en plus de PowerShell ; dites que vous voulez passer la chaîne à un programme C, qui s'attend intégré entre guillemets doubles à échapper comme \"
:
foo.exe "3\`" of rain"
Notez comment à la fois `"
- pour faire PowerShell heureux - et la \
- pour que le programme cible heureux - doit être présent.
La même logique vaut pour appeler un fichier batch, où ""
doit être utilisé:
foo.bat "3`"`" of rain"
En revanche, l'intégration à -quotes dans à double chaîne entre guillemets aucune fuite du tout.
simple -quotes intérieur à chaînes -quoted faire pas besoin supplémentaire échapper; considérer '2'' of snow'
, qui est la représentation « de PowerShell 2' of snow
.
foo.exe '2'' of snow'
foo.bat '2'' of snow'
PowerShell se traduit par des chaînes entre guillemets simples à les guillemets doubles avant de les transmettre au programme cible.
Cependant, à double -quotes intérieur à chaînes -quoted , qui ne ont pas besoin pour échapper à PowerShell , ne doivent encore être échappé pour le programme cible :
foo.exe '3\" of rain'
foo.bat '3"" of rain'
PowerShell v3 introduit la magie option --%
, appelé symbole stop-analyse syntaxique , ce qui atténue quelque peu la douleur, en passant quoi que ce soit après il non interprété au programme cible, sauf pour les références variables d'environnement de style cmd.exe
(par exemple, %USERNAME%
), qui sont élargi; par exemple:.
foo.exe --% "3\" of rain" -u %USERNAME%
Notez comment échapper à la "
intégré comme \"
pour le programme cible (et non aussi pour PowerShell comme \`"
) suffit.
Cependant, cette approche:
- ne permet pas de échapper caractères
%
afin d'éviter des extensions variables d'environnement. - exclut directement utiliser des variables et des expressions PowerShell; à la place, la ligne de commande doit être construite dans une variable de chaîne dans une première étape, puis appelé avec
Invoke-Expression
dans une seconde.
Ainsi, en dépit de ses nombreuses avancées, PowerShell n'a pas fait échapper beaucoup plus facile lors de l'appel des programmes externes. cependant, il a introduit un soutien pour les chaînes entre guillemets simples.
Je me demande s'il est fondamentalement possible dans le monde Windows pour passer toujours au modèle Unix de laisser le shell faire tout le retrait de tokens et citation on pouvait s'y attendre , à l'avant , quel que soit le programme cible , puis appeler le programme cible en faisant passer les jetons obtenus.
En complément excellente réponse mklement0:
Presque tous acceptent executables \"
comme un "
échappé. une utilisation sûre dans cmd est cependant presque possible en utilisant DELAYEDEXPANSION.
Pour envoyer un "
littéral explicitement à un processus, à attribuer \"
une variable d'environnement, et ensuite utiliser cette variable, chaque fois que vous devez passer un devis. Exemple:
SETLOCAL ENABLEDELAYEDEXPANSION
set q=\"
child "malicious argument!q!&whoami"
Note SETLOCAL ENABLEDELAYEDEXPANSION
semble fonctionner que dans des fichiers batch. Pour obtenir DELAYEDEXPANSION dans une session interactive, commencez cmd /V:ON
.
Si votre batchfile does't travail 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 passer un contenu dynamique à partir d'une variable qui contient des citations qui ont réussi à sortir ""
vous pouvez remplacer ""
avec \"
sur l'expansion:
SETLOCAL ENABLEDELAYEDEXPANSION
foo.exe "danger & bar=region with !dynamic_content:""=\"! & danger"
ENDLOCAL
Ce remplacement n'est pas en sécurité 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 permettant même temporairement DELAYEDEXPANSION n'est pas une option, continuez à lire:
Utilisation \"
à l'intérieur cmd est un peu plus sûr si on a toujours besoin d'échapper à des caractères spéciaux, au lieu de juste parfois. (Il est moins susceptible d'oublier un caret, si elle est cohérente ...)
Pour ce faire, l'un précède une citation avec un caret (^"
), des citations qui devraient atteindre le processus d'enfant littéraux doivent en outre être échappé avec un jeu (\^"
). tous shell caractères meta doivent être échappés avec ^
ainsi, par exemple &
=> ^&
; |
=> ^|
; >
=> ^>
; etc.
Exemple:
child ^"malicious argument\^"^&whoami^"
Source: Tout le monde cite les arguments de ligne de commande dans le mauvais sens , voir « Une meilleure méthode de citer »
Pour passer du contenu dynamique, il faut vérifier les points suivants:
La partie de la commande qui contient la variable doit être considérée comme « cité » par cmd.exe
(Ceci est impossible si la variable peut contenir des citations - ne pas écrire %var:""=\"%
). Pour ce faire, la dernière "
avant la variable et la première "
après la variable ne sont pas ^
-échappé. cmd-métacaractères entre ces deux "
ne doivent pas être échappé. Exemple:
foo.exe ^"danger ^& bar=\"region with %dynamic_content% & danger\"^"
Ce n'est pas sûr, si %dynamic_content%
peut contenir des guillemets non.
Par exemple pour le moteur Unreal outil d'automatisation de la gestion fichier batch - cela a fonctionné pour moi
par exemple: -cmdline = "-Messaging" -device = dispositif -addcmdline = "- sessionId = Session -SessionOwner = 'propriétaire' -SessionName = 'Build' -dataProviderMode = -LogCmds locales = 'LogCommodity OFF' -execcmds liste d'automatisation '; runtests essais séparés + + by + T1 + T2; quitter »" -run
Espérons que cela aide quelqu'un, a travaillé pour moi.