Sous-routine d'appel où le paramètre contient esperluette dans un fichier de commandes

5

Comment appeler un sous-programme dont le paramètre est une variable contenant une esperluette (& amp;)?

Il n'y a pas d'erreur, mais l'appel ne semble jamais s'exécuter.

exemple.bat

@echo off
setlocal enableDelayedExpansion

rem Doesn't work
set val=with^&ampersand
call :Output !val!

rem Works fine
set val=without_ampersand
call :Output !val!
goto End

:Output
set "line=%1"
echo Called: !line!
goto :eof

End:

Sortie:

Appelé: without_ampersand

Modifier:

L'utilisation de Expansion retardée n'est pas requis. C'était juste utilisé dans cet exemple. Une façon de le faire sans utiliser delayExpansion est préférable.

La question se concentre sur "Comment appeler" plutôt que "Comment définir initialement la variable". La variable peut provenir d'une entrée utilisateur ou d'un for /f boucle (comme c'est mon cas).

ANisus
la source
& amp; est un personnage réservé, que vous devez échapper stackoverflow.com/questions/1741546/…
spikey_richie
@spikey_richie Dans mon exemple, je l'ai échappé en utilisant ^. Mais cela ne transmettra pas la valeur au sous-programme.
ANisus
Vous utilisez une expansion retardée, alors je suppose que vous pourriez avoir besoin beaucoup plus s'échapper ...
grawity
Si vous revenez à l'essentiel et ne définissez que val = test ^ & test à l'invite de commande, exécutez simplement set sans valeur. La liste renvoie-t-elle val = test & test?
spikey_richie
Comme dit grawity .... essayer set val=with^^^&ampersand donc beaucoup plus échapper.
Pimp Juice IT

Réponses:

2

Les règles d’échappement par lots sont plutôt désagréables, mais le comportement est totalement prévisible si vous connaissez les règles.

L'information dont vous avez besoin pour comprendre le problème est disponible à l'adresse Comment le Windows Command Interpreter (CMD.EXE) analyse-t-il les scripts? dans les phases 1, 2, 5 et 6 de la réponse acceptée. Mais bonne chance pour absorber cette information à tout moment :-)

Deux problèmes de conception fondamentaux sont à l'origine de votre problème:  - La phase 6 double tous les carets, ce qui relance ensuite la phase 2 (en réalité les phases 1, 1.5 et 2).  - Mais la phase 2 nécessite & être échappé comme ^&. Notez que ce doit être un seul ^, pas doublé!

La seule façon d’obtenir votre approche au travail est d’introduire le ^ après la phase 6, le nombre de caret a doublé.

@echo off
setlocal enableDelayedExpansion
set "ESC=^"

rem Calling with delayed expansion value
set "val=with%%ESC%%&ampersand"
call :Output !val!

rem Calling with a string literal
call :Output with%%ESC%%^&ampersand

exit /b

:Output
set "line=%1"
echo Called: !line!
goto :eof

ESC est défini pour tenir ^.
Le premier tour de la phase 1 se développe %%ESC%% à %ESC%
le second tour de la phase 1 (initié par la phase 6) se développe %ESC% à ^

Tout cela est totalement irréalisable, surtout si vous ne savez pas ce que le contenu va être.

La seule stratégie sensée pour passer de manière fiable une valeur dans une routine CALLed consiste à passer par référence. Transmettez le nom d'une variable contenant la valeur de chaîne et développez cette valeur dans votre sous-routine à l'aide de l'expansion retardée.

@echo off
setlocal enableDelayedExpansion
set "val=with&ampersand"
call :Output val
exit /b

:Output
set "line=!%~1!"
echo Called: !line!
exit /b
dbenham
la source
Sensationnel. D'accord. Ce lien était informatif et plutôt effrayant à lire :). Mais l'option de passer par référence semble être la vraie solution dans ce cas. Merci pour la réponse bien écrite!
ANisus
0

Si vous ajoutez un supplément ^ et guillemets ça va marcher:

@echo off
setlocal enableDelayedExpansion

rem Doesn't work
set "val=with^^&ampersand"
call :Output !val!

rem Works fine
set "val=without_ampersand"
call :Output !val!
goto End

:Output
set "line=%1"
echo Called: !line!
goto :eof

SET LOCAL EnableDelayedExpansion nécessite 2 caractères d'échappement:

ECHO 123 ^^& 456^^! va sortir 123 & 456!.

Vous devriez aussi utiliser SET toujours avec des guillemets!

FatalBulletHit
la source
Puisqu'il s'agit de l'appel (plutôt que du paramètre) qui est en cause, voulez-vous dire que je dois faire un remplacement ( set val=!val:^&=^^^^^&! ) avant l'appel? Cela ne semble pas fonctionner.
ANisus
Nope - Cela ne peut pas fonctionner à cause du double de l'appel CALL
dbenham
@ANisus A surveillé cela, désolé. Mais avez-vous vraiment besoin de & combiné avec call Là? Si tel est le cas, vous pouvez éditer la variable et remplacer le & avec quelque chose d'autre que vous remplacez à nouveau par un & plus tard. Ou vous utilisez simplement le mot and (si c'est le but de la & ici).
FatalBulletHit