我编写了以下批处理脚本来回显文件夹的路径。
set TW_prod_cer_path=D:\prod_path
set /p client="Enter client: "
if %client% equ TW (
setlocal enabledelayedexpansion
set prod_path=!client!_prod_cer_path
echo !prod_path!
echo %!prod_path!%
)
我得到了以下输出
Enter client: TW
TW_prod_cer_path
ECHO is off.
但我预期的输出是:
Enter client: TW
TW_prod_cer_path
D:\prod_path
有人可以解释一下这种情况的原因以及需要采取什么纠正措施才能获得预期的输出吗?
答案1
第一个问题是非-delayed 扩展 –%…%
对整个if
语句(包括其整个括号内的块)进行扩展。(这是解析器技巧;cmd 仍然将整个语句视为单个命令行。)
换句话说,%…%
这里的扩张发生前尽管命令高于该值,但命令set
仍已到达。
第二个问题是,你搞错了延迟/非延迟扩展顺序。如果你想“取消引用”一个变量,你需要在稍后扩展它的名称,但更早;例如
set foo=value
set bar=foo
echo !%bar%!
您是否考虑过其他编程语言,例如 PowerShell?它具有哈希表:
$prod_paths = @{
"TW" = "D:\prod_path";
}
$client = Read-Host -Prompt "Enter client"
if ($client -ceq "TW") {
echo $prod_paths.Item($client)
}
答案2
当if
命令被解析时,解析器会看到
echo %!prod_path!%
这里存在一个问题:正常扩展(%var%
)在延迟扩展()之前执行,!var!
因此当变量名称仍未定义时,此代码会尝试检索变量的内容。
当然,逆语法也行不通
echo !%prod_path%!
在这种情况下,变量的名称在解析时被评估,但是在解析时变量仍然没有值,因此当发生延迟扩展时,没有变量名称可读取。
你需要一个双重延迟扩展,也就是说你需要类似的东西
echo !!prod_path!!
但这不是一个有效的语法。
因此,我们需要使用延迟扩展来检索我们需要读取的变量的名称,然后使用延迟扩展来检索变量内的值。
最简单的解决方案是改变代码结构来避免该问题(call
子程序,使用goto
,...),但还有另一种选择。
for %%a in (!prod_path!) do echo !%%a!
检索变量的名称(第一次延迟扩展),将检索到的值存储在for
可替换参数中,然后读取可替换参数引用的变量中的值(第二次延迟扩展)