As regras de escape em lote são bastante desagradáveis, mas o comportamento é totalmente previsível se você conhece as regras.
A informação que você precisa para entender o problema está disponível em Como o Windows Command Interpreter (CMD.EXE) analisa scripts? nas fases 1, 2, 5 e 6 da resposta aceita. Mas boa sorte a absorver essa informação a qualquer momento: -)
Existem dois problemas fundamentais de design que levam ao seu problema:
- A fase 6 duplica todos os carets, que então reinicia a fase 2 (na verdade, fases 1, 1.5 e 2).
- Mas a fase 2 requer que &
seja salvo como ^&
. Note que deve ser um único ^
, não duplicado!
A única maneira de fazer com que sua abordagem funcione é introduzir o ^
após a duplicação do sinal de pico da fase 6.
@echo off
setlocal enableDelayedExpansion
set "ESC=^"
rem Calling with delayed expansion value
set "val=with%%ESC%%&ersand"
call :Output !val!
rem Calling with a string literal
call :Output with%%ESC%%^&ersand
exit /b
:Output
set "line=%1"
echo Called: !line!
goto :eof
ESC está definido para armazenar ^
.
A primeira rodada da fase 1 expande %%ESC%%
para %ESC%
a segunda rodada da fase 1 (iniciada pela fase 6) expande %ESC%
para ^
Isso é totalmente impraticável, especialmente se você não souber qual será o conteúdo.
A única estratégia sensata para passar de forma confiável qualquer valor para uma rotina CALLed é passar por referência. Passe o nome de uma variável que contém o valor da string e expanda esse valor dentro de sua sub-rotina usando a expansão atrasada.
@echo off
setlocal enableDelayedExpansion
set "val=with&ersand"
call :Output val
exit /b
:Output
set "line=!%~1!"
echo Called: !line!
exit /b