在批处理文件中调用参数包含“&”符号的子例程

在批处理文件中调用参数包含“&”符号的子例程

如何调用一个参数为包含与号 (&) 的变量的子程序?

没有错误,但是调用似乎从未执行。

例子.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:

输出:

调用:without_ampersand

编辑:

使用延缓扩张不是必需的。它只是在本例中使用。最好不使用 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%^

这一切都是完全不切实际的,特别是当你不知道内容是什么的时候。

将任何值可靠地传递到被调用例程的唯一合理策略是通过引用传递。传递包含字符串值的变量的名称,然后使用延迟扩展在子例程中扩展该值。

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

您还应该SET始终使用引号!

答案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(变量定义)开始,然后是参数(变量使用),最后是命令(变量使用)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

相关内容