如何调用一个参数为包含与号 (&) 的变量的子程序?
没有错误,但是调用似乎从未执行。
例子.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:
输出:
调用: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%%&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%
到^
这一切都是完全不切实际的,特别是当你不知道内容是什么的时候。
将任何值可靠地传递到被调用例程的唯一合理策略是通过引用传递。传递包含字符串值的变量的名称,然后使用延迟扩展在子例程中扩展该值。
@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
始终使用引号!
答案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&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