Windows 批处理脚本:\MyProg此时意外出现
我有一个简单的批处理脚本test.bat,它通过命令行参数进行迭代:Windows 批处理脚本:\MyProg此时意外出现,windows,batch-file,Windows,Batch File,我有一个简单的批处理脚本test.bat,它通过命令行参数进行迭代: @echo off set prefix=C:\Program Files\MyProg for %%x in (%*) do ( echo %prefix% ) 此版本的脚本在cmd.exe中正常工作: C:\>test a b C:\Program Files\MyProg C:\Program Files\MyProg 但是,如果我修改批处理文件使其具有不同的前缀值,则添加(x86): 脚本失败: C:
@echo off
set prefix=C:\Program Files\MyProg
for %%x in (%*) do (
echo %prefix%
)
此版本的脚本在cmd.exe中正常工作:
C:\>test a b
C:\Program Files\MyProg
C:\Program Files\MyProg
但是,如果我修改批处理文件使其具有不同的前缀
值,则添加(x86)
:
脚本失败:
C:\>test a b
\MyProg was unexpected at this time.
真是一场灾难!如何解决此问题?使用启用!前缀代码>解决此问题:
@echo off
set prefix=C:\Program Files (x86)\MyProg
setlocal EnableDelayedExpansion
for %%x in (%*) do (
echo !prefix!
)
endlocal
!!难以置信 尽管您发现delayedexpansion
解决了括号内代码块内部的问题,但考虑到现有示例,您不需要代码块,因此可以不使用括号和delayedexpansion
。还建议双引号引用set变量和值,以消除可能出现的空白:
@echo off
set "prefix=C:\Program Files (x86)\MyProg"
for %%x in (%*) do echo %prefix%
我还假设您也想以某种方式使用%%x
,因此:
@echo off
set "prefix=C:\Program Files (x86)\MyProg"
for %%x in (%*) do echo %prefix%\%%~x
我建议先读一读
在使用命令块执行命令之前,Windows命令处理器将解析整个代码块,从(
开始,以匹配的结束)
。在处理命令块的过程中,%variable%
格式中的所有环境变量引用都将被环境变量的当前值替换,或者在一个根本不存在的环境变量上被删除。因此,最终执行的命令块不再包含任何%variable%
。这种行为很好地解释了
那么代码呢
set prefix=C:\Program Files (x86)\MyProg
for %%x in (%*) do (
echo %prefix%
)
使用执行的结果
echo C:\Program Files (x86)\MyProg
右括号)
不在被括在“
中的参数字符串内。因此,Windows命令处理器将其解释为的命令命令块的结尾
在
被解释为命令块的结尾之后,在同一行上指定一个以上的命令,而不使用诸如&
或&
或|
之类的运算符,这在语法上是不正确的。因此\MyProg
在标记结束后被解释为语法上无效的命令f命令块
在命令提示窗口中运行cmd/?
的帮助输出在最后一页的末尾解释说,包含空格或其中一个字符的文件名&()[]{}^=;!'+,`
必须包含在“
中,才能对所有这些字符进行逐字解释,但除外代码>如果也启用了延迟环境变量扩展
在参数字符串周围使用“
不仅对文件名是必需的,而且对任何包含空格或其中一个字符的参数字符串&()[]{}^=;!'+,`~
或重定向操作符
也是必需的,它们也应该由cmd.exe
逐字解释
因此,一个解决方案是:
set prefix=C:\Program Files (x86)\MyProg
for %%x in (%*) do (
echo "%prefix%"
)
ECHO输出带有两个的前缀“
,但输出带有ECHO的文件/文件夹名时最好始终用双引号括起来
set "prefix=%ProgramFiles(x86)%\MyProg"
for %%I in (%*) do (
echo "%prefix%\%%~I"
)
另一种解决方案是转义)
,将^
解释为文字字符。在这种情况下,在将%prefix%
替换为分配给环境变量prefix
的字符串值后,带有echo
的行仍然具有^)
非常重要。因此,有必要定义带有插入符号的前缀
字符串,插入符号被解释为文字字符,这意味着在环境变量定义中,有两个^
是必需的
set prefix=C:\Program Files (x86^^)\MyProg
for %%x in (%*) do (
echo %prefix%
)
环境变量前缀
现在使用字符串值定义:
C:\Program Files (x86^)\MyProg
这将导致
FOR命令块将
)解释为文字字符
set "prefix=C:\Program Files (x86^)\MyProg"
for %%x in (%*) do (
echo %prefix%
)
还可以定义环境变量前缀
,并将其括在双引号中,以将插入符号^
解释为文字字符,从而避免将该字符加倍,否则将其解释为转义字符
set "prefix=C:\Program Files (x86^)\MyProg"
for %%x in (%*) do (
echo %prefix%
)
另一种解决方案是使用延迟环境变量扩展:
@echo off
set prefix=C:\Program Files (x86)\MyProg
setlocal EnableDelayedExpansion
for %%x in (%*) do (
echo !prefix!
)
endlocal
但是这个解决方案有一个问题,这是由于命令行的双重解析造成的,因为启用了延迟扩展,这可以在将代码修改为
@echo off
set prefix=C:\Program Files (x86)\MyProg
setlocal EnableDelayedExpansion
for %%x in (%*) do (
echo !prefix!\%%~x
)
endlocal
并使用三个参数执行批处理文件Hello代码>和测试
和开始代码>。由于启用了延迟扩展,感叹号不再解释为文字字符。因此,输出为:
C:\Program Files (x86)\MyProg\Hello
但结果应该是:
C:\Program Files (x86)\MyProg\Hello!
C:\Program Files (x86)\MyProg\Test
C:\Program Files (x86)\MyProg\Start!
此输出可通过以下方式获得:
set "prefix=C:\Program Files (x86^)\MyProg"
for %%x in (%*) do (
echo %prefix%\%%~x
)
但是,真正安全的方法是打印包含在双引号中的串联字符串
set "prefix=%ProgramFiles(x86)%\MyProg"
for %%I in (%*) do (
echo "%prefix%\%%~I"
)
在本例中,上述示例的输出包含三个参数Hello代码>和测试
和开始代码>:
"C:\Program Files (x86)\MyProg\Hello!"
"C:\Program Files (x86)\MyProg\Test"
"C:\Program Files (x86)\MyProg\Start!"
另请参见我的回答,其中解释了为什么环境变量前缀
是使用“
左至变量名称并在分配给环境变量的字符串值末尾定义的。这是环境变量定义的推荐语法
此外,最好不要将区分大小写的解释修饰符存在的解释字母用作循环变量,否则结果可能是意外的,尤其是在动态连接的变量字符串上
例如:
@echo off
cls
echo Loop with %%~Xx:
for %%x in ("1" 2 3) do echo %%~Xx run.
echo Loop with %%~xX:
for %%X in ("1" 2 3) do echo %%~xX run.
echo Loop with %%~Ix:
for %%I in ("1" 2 3) do echo %%~Ix run.
echo Loop with %%~#x:
for %%# in ("1" 2 3) do echo %%~#x run.
pause
此小批量文件的输出为:
Loop with %~Xx:
run.
run.
run.
Loop with %~xX:
run.
run.
run.
Loop with %~Ix:
1x run.
2x run.
3x run.
Loop with %~#x:
1x run.
2x run.
3x run.
此处的目的是获取附加了x
的输出编号,而不是引用FOR的命令集中三个字符串的不存在的文件扩展名
因此,修饰符字母ADFNPSTXZadfnpstxz
不应用作循环变量,尽管在大多数情况下是可能的