Как вызвать подпрограмму, параметром которой является переменная, содержащая амперсанд (&)?
Ошибки нет, но вызов, похоже, не выполняется.
пример.bat
@echo off
setlocal enableDelayedExpansion
rem Doesn't work
set val=with^&ersand
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.
Вопрос сосредоточен на "Как мне вызвать", а не на "Как мне изначально задать переменную". Переменная может поступать из пользовательского ввода или из for /f
цикла (как в моем случае).
решение1
Правила пакетного выхода довольно отвратительны, но поведение полностью предсказуемо, если вы знаете правила.
Информация, необходимая для понимания проблемы, доступна по адресуКак интерпретатор команд 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%%&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 определен для удержания ^
.
Первый раунд фазы 1 расширяется %%ESC%%
до %ESC%
второго раунда фазы 1 (инициированного фазой 6) расширяется %ESC%
до^
Все это совершенно непрактично, особенно если вы не знаете, каким будет содержание.
Единственная разумная стратегия надежной передачи любого значения в CALLed-подпрограмму — это передача по ссылке. Передайте имя переменной, содержащей строковое значение, и расширьте это значение в вашей подпрограмме с помощью отложенного расширения.
@echo off
setlocal enableDelayedExpansion
set "val=with&ersand"
call :Output val
exit /b
:Output
set "line=!%~1!"
echo Called: !line!
exit /b
решение2
Если добавить дополнительные ^
кавычки, то это будет работать:
@echo off
setlocal enableDelayedExpansion
rem Doesn't work
set "val=with^^&ersand"
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
always с кавычками!
решение3
Другие ответы мне не подошли, так как & все еще считывался как разделитель команд, но я придумал это (последний цикл for приведен для демонстрации и должен быть изменен или удален по мере необходимости):
@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
решение4
Такие ядовитые символы, как , <>|&
безопасны в кавычках. Вам нужно использовать кавычки каждый раз, вам нужно обрабатывать (определять или использовать) их (или экранировать их). Это начинается с команды set
(определение переменной), продолжается параметром to call
(использование переменной) и продолжается (но далеко не заканчивается) командой echo
(использование переменной).
@echo off
setlocal
set "val=with&ersand"
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
Выход:
line=with&ersand
problem without quotes: with
Der Befehl "ampersand" ist entweder falsch geschrieben oder
konnte nicht gefunden werden.
ok with quotes: "with&ersand"
ok with escaping: with&ersand
ok with for: with&ersand