由于两个原因,不可能将字符串文字值hello " world
作为批处理参数传递:
无法在参数标记化方面转义空格。参数始终由未加引号的标记定界符分隔,即使它们是由^
转义字符前导的也是如此。参数标记定界符为{space}
、{tab}
、,
、;
、=
和{0xFF}
。包括定界符作为参数的唯一方法是确保定界符加上引号。
不可能在带引号的字符串中转义引号。引号是状态机:首次遇到引号会打开引号语义,后续的引号则关闭。下一个引号则再次打开,以此类推。如果关闭了引号,则可以使用^"
来转义引号字面量以保持关闭引号。但是一旦开始引用,那么就没有办法转义结束引号:下一个引号总是关闭引用。
因此,无论您如何添加引号和/或转义引号,始终会存在一个未加引号的空格,因此该字符串将被视为两个参数。
您可以采用Hapax推荐的策略——引用整个字符串,并将字符串中的任何引号字面值加倍:"Hello "" world"
。
但是我会稍作修改,使用%~1
而不是%1
以删除外部引号。然后,应将加倍的引号转换回单引号:
@echo off
set "arg1=%~1"
set "arg1=%arg1:""="%"
echo %arg1%
但是将字符串字面量作为批处理参数传递可能存在其他潜在问题。最阴险的问题是插入字符(caret)会被加倍。如果调用者使用CALL,则无法将带引号的插入符作为参数传递。我不会深入介绍问题的机制。如果您想了解更多信息,请参见https://dev59.com/6G855IYBdhLWcg3w5Igb#4095133。但以下示例说明了问题:
test.bat
@echo %1
-- 示例cmd会话 --
D:\test>test "^"
"^"
D:\test>call test "^"
"^^"
由于传递字符串文字作为批处理参数时存在许多复杂性,在高级批处理脚本中使用的最有效策略是将值存储在环境变量中,然后将变量名称作为参数进行传递。批处理脚本可以使用延迟扩展来获取正确的值:
test2.bat
@echo off
setlocal enableDelayedExpansion
set "arg1=!%1!"
echo !arg1!
-- 示例cmd会话 --
D:\test>set "myVar=Hello world! ^&|<>" How are you doing? !^^^&^|^<^>^"
D:\test>set myVar
myVar=Hello world! ^&|<>" How are you doing? !^&|<>
D:\test>test2 myVar
Hello world! ^&|<>" How are you doing? !^&|<>
D:\test>call test2 myVar
Hello world! ^&|<>" How are you doing? !^&|<>
^"
来实现。在批处理/cmd控制台中,“^”是转义字符。 - rojo