J'ai rencontré ss64.com , qui fournit une aide précieuse sur la procédure à suivre pour écrire des scripts de traitement par lots que l'interpréteur de commandes Windows exécutera.
Cependant, je suis incapable de trouver une bonne explication de la grammaire des scripts de traitement par lots, de la manière dont les choses se développent ou ne se développent pas, et de la manière de les échapper.
Voici des exemples de questions que je n'ai pas pu résoudre:
foreach $i (@ARGV) { print '*' . $i ; }
), l'a compilé et appelé ainsi: my_script.exe "a ""b"" c"
→ la sortie est *a "b*c
my_script.exe """a b c"""
→ l'affiche *"a*b*c"
echo
? Qu'est-ce qui est développé dans cette commande?for [...] %%I
Dans les scripts de fichiers, mais for [...] %I
Dans les sessions interactives?%PROCESSOR_ARCHITECTURE%
? J'ai trouvé que echo.exe %""PROCESSOR_ARCHITECTURE%
Fonctionne, existe-t-il une meilleure solution?%
Correspondent-elles? Exemple:set b=a
, echo %a %b% c%
→ %a a c%
set a =b
, echo %a %b% c%
→ bb c%
set
? Par exemple, si je fais set a=a" b
Puis echo.%a%
, J'obtiens a" b
. Si toutefois j'utilise echo.exe
De UnxUtils, j'obtiens a b
. Comment se fait-il que %a%
Se développe différemment?Merci pour tes lumières.
Nous avons effectué des expériences pour étudier la grammaire des scripts batch. Nous avons également étudié les différences entre le mode batch et le mode ligne de commande.
Voici un bref aperçu des phases du traitement d’une ligne de code dans un fichier de commandes:
Phase 0) Ligne de lecture:
Phase 1) Pourcentage d'expansion:
Phase 1.5) Supprimer <CR>
: Supprimer tous les caractères de retour à la ligne (0x0D)
Phase 2) Traiter les caractères spéciaux, créer des jetons et construire un bloc de commande en cache: Il s'agit d'un processus complexe qui est affecté par des éléments tels que des guillemets, des caractères spéciaux , délimiteurs de jetons et échappements de curseur.
Phase 3) Écho de la ou des commandes analysées uniquement si le bloc de commandes n'a pas commencé par @
Et qu'ECHO était activé à la début de l'étape précédente.
Phase 4) Extension de la variable FOR %X
: Uniquement si une commande FOR est active et que les commandes suivantes sont en cours de traitement.
Phase 5) Expansion retardée: Uniquement si l'expansion retardée est activée
Phase 5.3) Traitement du tuyau: Uniquement si les commandes sont situées de part et d'autre d'un tuyau
Phase 5.5) Exécuter la redirection:
Phase 6) Traitement des appels/Doublure de carets: Uniquement si le jeton de commande est CALL
Phase 7) Execute: La commande est exécutée.
Voici les détails pour chaque phase:
Notez que les phases décrites ci-dessous ne sont qu'un modèle du fonctionnement de l'analyseur de lot. Les éléments internes réels de cmd.exe peuvent ne pas refléter ces phases. Mais ce modèle est efficace pour prédire le comportement des scripts batch.
Phase 0) Ligne de lecture: Lisez la ligne d'entrée en commençant par le premier <LF>
.
<Ctrl-Z>
(0x1A) est lu comme suit: <LF>
(LineFeed 0x0A)<Ctrl-Z>
Est traité comme tel - il est not converti en <LF>
Phase 1) Pourcentage d'expansion:
%%
Est remplacé par un simple %
%*
, %1
, %2
, Etc.)%var%
, Si var n'existe pas, ne le remplacez par rien<LF>
Pas dans l'extension %var%
Phase 1.5) Supprimer <CR>
: Supprimer tous les retours chariot (0x0D) de la ligne.
Phase 2) Traiter les caractères spéciaux, créer des jetons et construire un bloc de commande en cache: Il s'agit d'un processus complexe qui est affecté par des éléments tels que des guillemets, des caractères spéciaux , délimiteurs de jetons et échappements de curseur. Ce qui suit est une approximation de ce processus.
Certains concepts sont importants tout au long de cette phase.
<space>
<tab>
;
,
=
<0x0B>
<0x0C>
Et <0xFF>
Les caractères suivants peuvent avoir une signification particulière dans cette phase, selon le contexte: ^
(
@
&
|
<
>
<LF>
<space>
<tab>
;
,
=
<0x0B>
<0x0C>
<0xFF>
Regardez chaque personnage de gauche à droite:
^
), Le caractère suivant est échappé et le signe d'insertion est supprimé. Les caractères échappés perdent toute signification particulière (à l'exception de <LF>
)."
), Activez/désactivez l'indicateur de citation. Si l'indicateur de citation est actif, seuls "
Et <LF>
Sont spéciaux. Tous les autres caractères perdent leur signification particulière jusqu'à ce que la citation suivante active le drapeau de citation. Il n'est pas possible d'échapper à la citation finale. Tous les caractères cités sont toujours dans le même jeton.<LF>
Désactive toujours l'indicateur de citation. D'autres comportements varient en fonction du contexte, mais les guillemets ne modifient jamais le comportement de <LF>
. <LF>
<LF>
Est dépouillé<LF>
, Il est traité comme un littéral, ce qui signifie que ce processus n'est pas récursif.<LF>
Pas entre parenthèses <LF>
Est supprimé et l'analyse de la ligne en cours est terminée.<LF>
Dans un bloc FOR IN entre parenthèses <LF>
Est converti en un <space>
<LF>
Dans un bloc de commande entre parenthèses <LF>
Est converti en <LF><space>
, Et le <space>
Est traité comme faisant partie de la ligne suivante du bloc de commandes.&
|
<
Ou >
, Divisez la ligne à ce stade afin de gérer les canaux, la concaténation de commandes et redirection. |
), Chaque côté est une commande séparée (ou un bloc de commandes) qui obtient un traitement spécial en phase 5.3.&
, &&
Ou ||
, Chaque côté de la concaténation est traité comme une commande distincte.<
, <<
, >
Ou >>
, La clause de redirection est analysée, temporairement supprimée, puis ajoutée à la fin de la commande en cours. Une clause de redirection comprend un chiffre de descripteur de fichier facultatif, l'opérateur de redirection et le jeton de destination de la redirection. @
, Alors le @
A une signification particulière. (@
N'est pas spécial dans aucun autre contexte) @
Est supprimée.@
Est avant une ouverture (
, Le bloc entier entre parenthèses est exclu de l'écho de la phase 3.(
N'est pas spécial.(
, Lancez une nouvelle instruction composée et incrémentez le compteur de parenthèses.)
Termine l'instruction composée et décrémente le compteur de parenthèses.)
Fonctionne comme une instruction REM
à condition qu'elle soit immédiatement suivie d'un délimiteur de jeton, d'un caractère spécial, d'une nouvelle ligne, ou fin de fichier ^
(La concaténation de ligne est possible)@
Spéciaux aient été supprimés et que la redirection soit déplacée à la fin). (
Fonctionne comme un délimiteur de jeton de commande, en plus des délimiteurs de jetons standard.<LF>
Comme <space>
. Une fois la clause IN analysée, tous les jetons sont concaténés pour former un seul jeton.^
Non échappé qui termine la ligne, le jeton d'argument est alors jeté et la ligne suivante est analysée et ajoutée au REM. Cela se répète jusqu'à ce qu'il y ait plus d'un jeton ou que le dernier caractère ne soit pas ^
.:
Et qu'il s'agit du premier tour de la phase 2 (pas un redémarrage en raison de CALL en phase 6), alors )
, <
, >
, &
Et |
N'ont plus de signification particulière. Le reste de la ligne est considéré comme faisant partie de l’étiquette "commande".^
Continue d'être spécial, ce qui signifie que la continuation de ligne peut être utilisée pour ajouter la ligne suivante à l'étiquette.(
N'a plus de signification particulière pour la première commande suivant le Libellé non exécuté.|
Ou &
, &&
Ou ||
Sur la ligne. Phase 3) Écho de la ou des commandes analysées uniquement si le bloc de commandes n'a pas commencé par @
Et qu'ECHO était activé à la début de l'étape précédente.
Phase 4) Extension de la variable FOR %X
: Uniquement si une commande FOR est active et que les commandes suivantes sont en cours de traitement.
%%X
En %X
. La ligne de commande a différentes règles d'expansion en pourcentage pour la phase 1. C'est la raison pour laquelle les lignes de commande utilisent %X
Mais les fichiers de traitement par lots utilisent %%X
Pour les variables FOR.~modifiers
Ne le sont pas.~modifiers
A priorité sur les noms de variables. Si un caractère suivant ~
Est à la fois un modificateur et un nom de variable FOR valide, et s'il existe un caractère ultérieur qui est un nom de variable FOR actif, il est interprété comme un modificateur.---- À partir de ce moment, chaque commande identifiée lors de la phase 2 est traitée séparément.
---- Les phases 5 à 7 sont terminées pour une commande avant de passer à la suivante.
Phase 5) Expansion retardée: Uniquement si l'expansion retardée est activée, la commande n'est pas dans un bloc entre parenthèses de part et d'autre d'un tuya , et la commande n'est pas un script de lot "naked" (nom de script sans parenthèses, CALL, concaténation de commandes ou canal).
!
. Sinon, le jeton n'est pas analysé - important pour les caractères ^
. Si le jeton contient !
, Scannez chaque caractère de gauche à droite: ^
), Le caractère suivant n'a pas de signification particulière, le curseur est supprimé.!
Sont réduites en un seul !
!
Non apparié restant est supprimé<CR>
Ou <LF>
) Phase 5.3) Traitement du tuyau: Uniquement si les commandes sont situées de part et d'autre d'un tuyau
Chaque côté du tuyau est traité indépendamment et de manière asynchrone.
%comspec% /S /D /c" commandBlock"
, De sorte que le bloc de commande reçoit un phase restart, mais cette fois en mode ligne de commande. <LF>
Avec une commande avant et après sont convertis en <space>&
. Les autres <LF>
Sont supprimés.Phase 5.5) Exécuter la redirection: Toute redirection découverte en phase 2 est maintenant exécutée.
||
Est utilisé .Phase 6) Traitement des appels/Doublure de curseur: Uniquement si le jeton de commande est CALL ou si le texte précédant le premier délimiteur de jetons standard est CALL. Si CALL est analysé à partir d'un jeton de commande plus volumineux, la portion inutilisée est ajoutée au jeton arguments avant de continuer.
/?
Sans guillemets. Si vous en trouvez un dans les jetons, annulez la phase 6 et passez à la phase 7, où l’aide HELP for CALL sera imprimée.CALL
, afin que plusieurs appels puissent être empilés&
Ou |
(
@
IF
ou FOR
n'est pas reconnu en tant que commande interne ou externe.:
.:
, Alors Phase 7) Execute: La commande est exécutée.
+
/
[
]
<space>
<tab>
,
;
Ou =
.
\
Ou :
+
/
[
]
<space>
<tab>
,
;
Ou =
/?
Est détecté. La plupart reconnaissent /?
S'il apparaît n'importe où dans les arguments. Toutefois, quelques commandes telles que ECHO et SET n'impriment l'aide que si le premier jeton d'argument commence par /?
.set "name=content" ignored
-> valeur = content
set name="content" not ignored
-> valeur = "content" not ignored
::
Entraînera toujours une erreur, sauf si SUBST est utilisé pour définir un volume pour ::
::
, Le volume sera modifié, il ne sera pas traité comme une étiquette.<space>
,
;
Ou =
Et ajoutez le reste au (x) jeton (s) d’argument.:
, Passez à 7.4::
, Cela ne sera pas atteint car l'étape précédente sera abandonnée avec une erreur sauf si SUBST est utilisé pour définir un volume pour ::
.:
, Alors passez à 7.4::
, Et SUBST est utilisé pour définir un volume pour ::
, et le jeton de commande entier est un chemin valide pour une commande externe.:
.Fonctionne comme le BatchLine-Parser, sauf:
Phase 1) Pourcentage d'expansion:
%*
, %1
Etc.%var%
Reste inchangé.%%
. Si var = content, alors %%var%%
Devient %content%
.Phase 3) Écho de la ou des commandes analysées
Phase 5) Expansion retardée: uniquement si RetardedExpansion est activé
!var!
Reste inchangé.Phase 7) Execute Command
::
Il existe de nombreux contextes différents dans lesquels cmd.exe analyse les valeurs entières des chaînes et les règles sont incohérentes:
SET /A
IF
%var:~n,m%
(Expansion de sous-chaîne variable)FOR /F "TOKENS=n"
FOR /F "SKIP=n"
FOR /L %%A in (n1 n2 n3)
EXIT [/B] n
Les détails de ces règles peuvent être trouvés à Règles pour la façon dont CMD.EXE analyse les nombres
Pour ceux qui souhaitent améliorer les règles d'analyse de cmd.exe, il existe un sujet de discussion sur le forum DosTips où les problèmes peuvent être signalés et les suggestions formulées.
J'espère que ça aide
Jan Erik (jeb) - Auteur original et découvreur des phases
Dave Benham (dbenham) - Beaucoup de contenu et d'édition supplémentaires
Lors de l'appel d'une commande à partir d'une fenêtre de commande, la syntaxe des arguments de la ligne de commande n'est pas effectuée par cmd.exe
(a.k.a. "le shell"). Le plus souvent, la création de jetons est effectuée par le runtime C/C++ des processus nouvellement formés, mais ce n'est pas nécessairement le cas - par exemple, si le nouveau processus n'a pas été écrit en C/C++ ou si le nouveau processus choisit d'ignorer argv
et traite la ligne de commande brute pour elle-même (par exemple avec GetCommandLine () ). Au niveau du système d'exploitation, Windows transmet les lignes de commande non considérées comme une chaîne unique aux nouveaux processus. Ceci contraste avec la plupart des * shells nix, où le shell marque les arguments de manière cohérente et prévisible avant de les transmettre au processus nouvellement formé. Tout cela signifie que vous pouvez rencontrer un comportement très différent en ce qui concerne la numérotation des arguments entre les différents programmes de Windows, car chaque programme prend souvent les choses en main.
Si cela ressemble à de l'anarchie, c'est en quelque sorte. Cependant, puisqu'un grand nombre de programmes Windows utilisent le argv
du runtime de Microsoft C/C++, il peut être généralement utile de comprendre - comment le MSVCRT tokenize arguments. Voici un extrait:
Le "langage par lots" de Microsoft (.bat
) ne fait pas exception à cet environnement anarchique et a développé ses propres règles uniques pour la création de jetons et l’échappement. Il semble également que l'invite de commande de cmd.exe effectue un prétraitement de l'argument de ligne de commande (principalement pour la substitution et l'échappement de variable) avant de transmettre l'argument au processus en cours d'exécution. Vous pouvez en savoir plus sur les détails de bas niveau de la langue de traitement par lots et de l'échappement de cmd dans les excellentes réponses de Jeb et Dbenham sur cette page.
Construisons un utilitaire de ligne de commande simple en C et voyons ce qu'il dit à propos de vos cas de test:
int main(int argc, char* argv[]) {
int i;
for (i = 0; i < argc; i++) {
printf("argv[%d][%s]\n", i, argv[i]);
}
return 0;
}
(Remarques: argv [0] est toujours le nom de l'exécutable et est omis ci-dessous par souci de brièveté. Testé sous Windows XP SP3. Compilé avec Visual Studio 2005.)
> test.exe "a ""b"" c"
argv[1][a "b" c]
> test.exe """a b c"""
argv[1]["a b c"]
> test.exe "a"" b c
argv[1][a" b c]
Et quelques uns de mes propres tests:
> test.exe a "b" c
argv[1][a]
argv[2][b]
argv[3][c]
> test.exe a "b c" "d e
argv[1][a]
argv[2][b c]
argv[3][d e]
> test.exe a \"b\" c
argv[1][a]
argv[2]["b"]
argv[3][c]
Voici une explication détaillée de la phase 1 dans réponse de jeb (valide pour le mode de traitement par lots et le mode de ligne de commande).
Phase 1) Pourcentage d'expansion En commençant par la gauche, scannez chaque caractère pour %
Ou <LF>
. Si trouvé alors
<LF>
) <LF>
, Alors <LF>
<CR>
)%
, Passez donc à 1.1%
) ignoré si mode de ligne de commande%
Alors%%
Par le simple %
Et continuez le scan*
Et que les extensions de commande sont activées, alors%*
Par le texte de tous les arguments de la ligne de commande (Remplacez par rien s'il n'y a pas d'argument) et continuez le scan.<digit>
Puis%<digit>
Par la valeur de l'argument (remplacez par rien si non défini) et continuez l'analyse.~
Et les extensions de commande sont activées, puis <digit>
Requis, alors%~[modifiers]<digit>
Par une valeur d'argument modifiée (remplacez-la par rien si non défini ou si spécifié, $ PATH: modificateur non défini) et poursuivez l'analyse.<digit>
%
Ou la fin du tampon, et appelez-les VAR (peut-être une liste vide) %
, Alors %VAR%
Par la valeur de VAR et continuez le scan%VAR%
Et continuez le scan%
:
Ou de la fin de la mémoire tampon, et appelez-les VAR (cette liste peut être vide). Si VAR se sépare avant :
Et que le caractère suivant est %
, Incluez :
Comme dernier caractère de VAR et séparez-le avant %
. %
, Alors %VAR%
Par la valeur de VAR et continuez le scan%VAR%
Et continuez le scan:
, Alors %VAR:
Et continuez le scan.~
, Alors [integer][,[integer]]%
, Alors%VAR:~[integer][,[integer]]%
Par une sous-chaîne de la valeur de VAR (pouvant entraîner une chaîne vide) et continuez l'analyse.=
Ou *=
Puis[*]search=[replace]%
, Où la recherche peut inclure tout jeu de caractères sauf =
, Et replace peut inclure tout jeu de caractères sauf %
, Puis remplacez%VAR:[*]search=[replace]%
Avec la valeur VAR après avoir effectué une recherche et un remplacement (ce qui peut entraîner une chaîne vide) et poursuivre l'analyse%
Et poursuivez l'analyse en commençant par le caractère suivant après le %
%
Et continuez votre analyse en commençant par le caractère suivant après le %
Ce qui précède aide à expliquer pourquoi ce lot
@echo off
setlocal enableDelayedExpansion
set "1var=varA"
set "~f1var=varB"
call :test "arg1"
exit /b
::
:test "arg1"
echo %%1var%% = %1var%
echo ^^^!1var^^^! = !1var!
echo --------
echo %%~f1var%% = %~f1var%
echo ^^^!~f1var^^^! = !~f1var!
exit /b
Donne ces résultats:
%1var% = "arg1"var
!1var! = varA
--------
%~f1var% = P:\arg1var
!~f1var! = varB
Note 1 - La phase 1 a lieu avant la reconnaissance des instructions REM. Ceci est très important car cela signifie qu'une remarque peut générer une erreur fatale si sa syntaxe de développement d'argument n'est pas valide ou si la syntaxe de recherche et de remplacement de variable n'est pas valide!
@echo off
rem %~x This generates a fatal argument expansion error
echo this line is never reached
Note 2 - Autre conséquence intéressante des règles d’analyse%: Les variables contenant: dans le nom peuvent être définies, mais ils ne peuvent être développés que si les extensions de commande sont désactivées. Il existe une exception: un nom de variable contenant un simple deux-points à la fin peut être développé lorsque les extensions de commande sont activées. Cependant, vous ne pouvez pas effectuer d'opération de sous-chaîne ou de recherche et remplacement sur des noms de variables se terminant par un signe deux-points. Le fichier de commandes ci-dessous (courtoisie de jeb) illustre ce problème.
@echo off
setlocal
set var=content
set var:=Special
set var::=double colon
set var:~0,2=tricky
set var::~0,2=unfortunate
echo %var%
echo %var:%
echo %var::%
echo %var:~0,2%
echo %var::~0,2%
echo Now with DisableExtensions
setlocal DisableExtensions
echo %var%
echo %var:%
echo %var::%
echo %var:~0,2%
echo %var::~0,2%
Note 3 - Un résultat intéressant de l'ordre des règles d'analyse que jeb énonce dans son message: Lors de l'exécution rechercher et remplacer avec l’extension normale, les caractères spéciaux ne doivent PAS être échappés (bien qu’ils puissent être cités). Mais lors de la recherche et du remplacement avec expansion retardée, les caractères spéciaux DOIVENT être évités (à moins qu’ils ne soient cités).
@echo off
setlocal enableDelayedExpansion
set "var=this & that"
echo %var:&=and%
echo "%var:&=and%"
echo !var:^&=and!
echo "!var:&=and!"
Voici une explication plus détaillée et plus précise de la phase 5 en réponse de jeb (Valable pour le mode de traitement par lots et le mode de ligne de commande)
Phase 5) Expansion retardée
Cette phase est ignorée si l’une des conditions suivantes est remplie:
CALL
, un bloc entre parenthèses, à toute forme de concaténation de commande (&
, &&
Ou ||
) Ou un tuyau |
.Le processus d'expansion retardée est appliqué aux jetons indépendamment. Une commande peut avoir plusieurs jetons:
for ... in(TOKEN) do
if defined TOKEN
if exists TOKEN
if errorlevel TOKEN
if cmdextversion TOKEN
if TOKEN comparison TOKEN
, Où comparaison est l'un de ==
, equ
, neq
, lss
, leq
, gtr
ou geq
Aucune modification n'est apportée aux jetons qui ne contiennent pas !
.
Pour chaque jeton qui contient au moins un !
, Scannez chaque caractère de gauche à droite pour trouver ^
Ou !
. S'il est trouvé,
!
Ou ^
^
, Alors ^
!
, Alors !
Ou <LF>
, Et appelez-les VAR (peut-être une liste vide) !
, Alors !VAR!
Par la valeur de VAR et continuez le scan!VAR!
Et continuez le scan!
, :
Ou <LF>
, Et appelez-les VAR (cette liste peut être vide). Si VAR se sépare avant :
Et que le caractère suivant est !
, Incluez :
Comme dernier caractère du VAR et coupez avant !
!
, Alors !VAR!
Par la valeur de VAR et continuez le scan!VAR!
Et continuez le scan:
, Alors !VAR:
Et continuez le scan~[integer][,[integer]]!
Alors!VAR:~[integer][,[integer]]!
Par une sous-chaîne de la valeur de VAR (résultant éventuellement en une chaîne vide) et continuez l'analyse[*]search=[replace]!
, Où la recherche peut inclure n’importe quel jeu de caractères sauf =
Et remplacer peut inclure tout jeu de caractères sauf !
,!VAR:[*]search=[replace]!
Par la valeur de VAR après une recherche et un remplacement (ce qui peut entraîner une chaîne vide) et continuez l'analyse!
!
!
Comme indiqué, les commandes reçoivent la totalité de la chaîne d'arguments dans μSoft land, et il leur appartient de les analyser en arguments séparés pour leur propre utilisation. Il n’ya pas de cohérence à cet égard entre différents programmes et, par conséquent, il n’existe pas un ensemble unique de règles pour décrire ce processus. Vous devez vraiment vérifier chaque cas de coin pour la bibliothèque C que votre programme utilise.
En ce qui concerne le système .bat
fichiers vont, voici ce test:
c> type args.cmd
@echo off
echo cmdcmdline:[%cmdcmdline%]
echo 0:[%0]
echo *:[%*]
set allargs=%*
if not defined allargs goto :eof
setlocal
@rem Wot about a Nice for loop?
@rem Then we are in the land of delayedexpansion, !n!, call, etc.
@rem Plays havoc with args like %t%, a"b etc. ugh!
set n=1
:loop
echo %n%:[%1]
set /a n+=1
shift
set param=%1
if defined param goto :loop
endlocal
Maintenant, nous pouvons exécuter des tests. Voyez si vous pouvez comprendre ce que μSoft essaie de faire:
C>args a b c
cmdcmdline:[cmd.exe ]
0:[args]
*:[a b c]
1:[a]
2:[b]
3:[c]
Bien jusqu'à présent. (Je laisserai de côté l'inintéressant %cmdcmdline%
et %0
à partir de maintenant.)
C>args *.*
*:[*.*]
1:[*.*]
Aucune extension de nom de fichier.
C>args "a b" c
*:["a b" c]
1:["a b"]
2:[c]
Pas de suppression des guillemets, bien que les guillemets empêchent la division des arguments.
c>args ""a b" c
*:[""a b" c]
1:[""a]
2:[b" c]
Les doubles guillemets consécutifs leur font perdre toutes leurs capacités d'analyse particulières. @ L'exemple de Beniot:
C>args "a """ b "" c"""
*:["a """ b "" c"""]
1:["a """]
2:[b]
3:[""]
4:[c"""]
Quiz: Comment passez-vous la valeur de n'importe quel environnement var en tant qu'argument nique (c'est-à-dire, en tant que %1
) dans un fichier chauve-souris?
c>set t=a "b c
c>set t
t=a "b c
c>args %t%
1:[a]
2:["b c]
c>args "%t%"
1:["a "b]
2:[c"]
c>Aaaaaargh!
Une analyse syntaxique semble à jamais brisée.
Pour votre divertissement, essayez d’ajouter divers ^
, \
, '
, &
(etc.) caractères à ces exemples.
Vous avez déjà d'excellentes réponses ci-dessus, mais pour répondre à une partie de votre question:
set a =b, echo %a %b% c% → bb c%
Qu'est-ce qui se passe là-bas est que parce que vous avez un espace avant le =, une variable est créée appelée %a<space>%
alors quand vous echo %a %
qui est évalué correctement comme b
.
La partie restante b% c%
est ensuite évalué comme texte brut + une variable non définie % c%
, qui devrait être repris comme il se doit, pour moi echo %a %b% c%
résultats bb% c%
Je soupçonne que la possibilité d'inclure des espaces dans les noms de variables est davantage un oubli qu'une "fonctionnalité" planifiée
edit: voir réponse acceptée, ce qui suit est faux et explique uniquement comment passer une ligne de commande à TinyPerl.
En ce qui concerne les citations, j’ai le sentiment que le comportement est le suivant:
"
est trouvé, la chaîne commence"
est globbed"
est trouvé:""
_ (donc un triple "
) alors un guillemet double est ajouté à la chaîne"
_ (donc un double "
), une citation double est ajoutée à la chaîne et la chaîne se termine"
, la fin de la chaîneEn bref:
"a """ b "" c"""
se compose de deux chaînes: a " b "
et c"
"a""
, "a"""
et"a""""
sont tous la même chaîne si à la fin d'une ligne