Chame a sub-rotina onde o parâmetro contém oe comercial no arquivo de grupo

5

Como eu chamo uma sub-rotina com um parâmetro sendo uma variável contendo um e comercial (&)?

Não há erro, mas a chamada nunca parece ser executada.

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

Saída:

Called: without_ampersand

Editar:

O uso de delayedExpansion não é obrigatório. Foi usado apenas neste exemplo. Uma maneira de fazer isso sem usar delayedExpansion é preferida.

A questão é se concentrar em "Como faço para chamar" em vez de "Como configuro inicialmente a variável". A variável pode vir da entrada do usuário ou de um loop for /f (como é o meu caso).

    
por ANisus 06.02.2018 / 12:27

2 respostas

2

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%%&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á 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&ampersand"
call :Output val
exit /b

:Output
set "line=!%~1!"
echo Called: !line!
exit /b
    
por 06.02.2018 / 17:19
0

Se você adicionar mais ^ e aspas, funcionará:

@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 requer 2 caracteres de escape:

ECHO 123 ^^& 456^^! produzirá 123 & 456! .

Você também deve usar SET sempre com aspas!

    
por 06.02.2018 / 13:00