Вызов подпрограммы, где параметр содержит амперсанд в пакетном файле

Вызов подпрограммы, где параметр содержит амперсанд в пакетном файле

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

Ошибки нет, но вызов, похоже, не выполняется.

пример.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.

Вопрос сосредоточен на "Как мне вызвать", а не на "Как мне изначально задать переменную". Переменная может поступать из пользовательского ввода или из 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%%&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

решение2

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

@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!.

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

решение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&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

Выход:

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

Связанный контент