Chame a sub-rotina onde o parâmetro contém E comercial no arquivo em lote

Chame a sub-rotina onde o parâmetro contém E comercial no arquivo em lote

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

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

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

Chamado: sem_ampersand

Editar:

O uso deExpansão atrasadanão é necessário. Foi usado apenas neste exemplo. É preferível uma maneira de fazer isso sem usar atrasadoExpansion.

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

Responder1

As regras de escape em lote são bastante desagradáveis, mas o comportamento é totalmente previsível se você conhecer as regras.

As informações que você precisa para entender o problema estão disponíveis emComo o Windows Command Interpreter (CMD.EXE) analisa scripts?nas fases 1, 2, 5 e 6 da resposta aceita. Mas boa sorte para absorver essa informação em breve :-)

Existem dois problemas fundamentais de design que levam ao seu problema: - A fase 6 duplica todos os sinais circunflexos, que então reinicia a fase 2 (na verdade, fases 1, 1.5 e 2). - Mas a fase 2 exige &ser escapada como ^&. Observe que deve ser single ^, não duplicado!

A única maneira de fazer sua abordagem funcionar é introduzi-la ^após a duplicação do sinal de intercalação da fase 6 ter ocorrido.

@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 é definido para segurar ^.
A primeira rodada da fase 1 se expande %%ESC%%para %ESC%
a segunda rodada da fase 1 (iniciada pela fase 6) se expande %ESC%para^

Tudo isso é totalmente impraticável, principalmente se você não sabe qual será o conteúdo.

A única estratégia sensata para passar qualquer valor de forma confiável para uma rotina CALL é 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 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

Responder2

Se você adicionar um adicional ^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 EnableDelayedExpansionrequer 2 caracteres de escape:

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

Você também deve usar SETsempre entre aspas!

Responder3

As outras respostas não funcionaram para mim, pois o & ainda estava sendo lido como um separador de comandos, mas eu descobri isso (o último loop for é para demonstração e deve ser modificado ou removido conforme necessário):

@echo off
setlocal enableDelayedExpansion

set "file=pathwith&orwithoutampersandand!exclamation"
call :execute
exit /b

:execute
for %%A in ("%file:!=" "%") do (
    if [!file_conc!]==[] (
        set "file_conc=%%A"
    ) else (
        set "file_conc=!file_conc!^^^!%%A"
    )
)
set "file=!file_conc:"=!"
set "file_conc="
for %%A in ("!file:&=" "!") do (
    if [!file_conc!]==[] (
        set "file_conc=%%A"
    ) else (
        set "file_conc=!file_conc!^^^&%%A"
    )
)
set "file=!file_conc:"=!"
set "file_conc="
for /f "tokens=*" %%A in ('cmd /c ""!file!" "%error_log%" %ldt%" 1^>nul') do stuff
exit /b

Responder4

Caracteres venenosos como <>|&estão seguros entre aspas. Você tem que usar aspas todas as vezes, tem que lidar (definir ou usar) elas (ou escapar delas). Isso começa com o setcomando (definição de variável), continua com o parâmetro para call(uso de variável) e continua (mas de longe não termina) com o echocomando (uso de variável).

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

:Output
set "line=%~1"
set line
echo problem without quotes: %line%
echo ok with quotes: "%line%"
echo ok with escaping: %line:&=^&%
for /f "delims=" %%a in ("%line%") do echo ok with for: %%a

Saída:

line=with&ampersand
problem without quotes: with
Der Befehl "ampersand" ist entweder falsch geschrieben oder
konnte nicht gefunden werden.
ok with quotes: "with&ampersand"
ok with escaping: with&ampersand
ok with for: with&ampersand

informação relacionada