5

Как вызвать подпрограмму с параметром, являющимся переменной, содержащей амперсанд (&)?

Там нет ошибки, но кажется, что вызов никогда не выполняется.

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:

Выход:

Вызывается: без_амперса

Редактировать:

Использование delayedExpansion не требуется. Это было просто использовано в этом примере. Способ сделать это без использования delayedExpansion является предпочтительным.

Вопрос сосредоточен на "Как мне позвонить", а не на "Как я изначально установил переменную". Переменная может исходить из пользовательского ввода или цикла for /f (как в моем случае).

2 ответа2

2

Правила пакетного выхода довольно неприятны, но поведение полностью предсказуемо, если вы знаете правила.

Сведения, необходимые для понимания проблемы, доступны по адресу Как интерпретатор сценариев команд Windows (CMD.EXE) анализирует сценарии? на этапах 1, 2, 5 и 6 принятого ответа. Но удачи, поглощающей эту информацию в ближайшее время :-)

Есть две фундаментальные проблемы проектирования, которые приводят к вашей проблеме:- Фаза 6 удваивает все каретки, а затем перезапускает фазу 2 (фактически фазы 1, 1.5 и 2). - Но фаза 2 требует & быть экранирована как ^& . Обратите внимание, что это должен быть один ^ , а не удвоенный!

Единственный способ добиться вашего подхода к работе - ввести ^ после того, как на этапе 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 определяется для проведения ^ .
Первый раунд фазы 1 расширяет %%ESC%% до %ESC%
второй раунд фазы 1 (инициированный фазой 6) расширяет %ESC% до ^

Это все абсолютно непрактично, особенно если вы не знаете, каким будет контент.

Единственная разумная стратегия для надежной передачи любого значения в процедуру CALLed - это передача по ссылке. Передайте имя переменной, содержащей строковое значение, и разверните это значение в подпрограмме, используя отложенное расширение.

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

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

Если вы добавите дополнительные ^ и кавычки, это будет работать:

@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 требует 2 управляющих символа:

ECHO 123 ^^& 456^^! выдаст 123 & 456! ,

Вы также должны использовать SET всегда с кавычками!

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .