如果我运行批处理文件
setlocal
chdir ..
目录没有改变,但如果我运行
setlocal
endlocal
chdir ..
它工作正常。这必须正是 setlocal 所期望的。但是,当你阅读setlocal的定义时并不完全清楚,这与如何看到环境变量有关。我希望这是一个很好的机会来解释 setlocal 的实际作用以及它为什么会干扰 chdir。
如果我运行批处理文件
setlocal
chdir ..
目录没有改变,但如果我运行
setlocal
endlocal
chdir ..
它工作正常。这必须正是 setlocal 所期望的。但是,当你阅读setlocal的定义时并不完全清楚,这与如何看到环境变量有关。我希望这是一个很好的机会来解释 setlocal 的实际作用以及它为什么会干扰 chdir。
help setlocal
SETLOCAL(或)的帮助文档setlocal /?
实际上很好地解释了这种情况。唯一不明显的是,“环境变化的本地化”不仅包括环境变量,还包括当前目录,以及延迟扩展和扩展状态。可能还有更多,但我现在想不起来。
让你绊倒的事情实际上得到了很好的解释:“当到达批处理脚本的末尾时,会为该批处理脚本发出的任何未完成的 SETLOCAL 命令执行隐含的 ENDLOCAL。 ” 没有说明的是同样适用于称为子程序。
当您的批处理脚本结束时,隐含的 ENDLOCAL “擦除”您的 CHDIR 的效果。您在第二个代码中的显式 ENDLOCAL 让您回到根环境,因此您的 CHDIR 将被保留。
更新
当前目录不是环境变量,即使您通常可以使用%CD%
. 您可以通过tring 来证明它SET CD
-它可能会给您“未定义环境变量CD”。如果您使用 明确定义自己的真实 CD 变量set "CD=some value"
,%CD%
则将返回您分配的值,而不是当前目录。
最初的 SETLOCAL 命令在旧 COMMAND.COM 时代无法控制延迟扩展或扩展。引入 CMD.EXE 时添加了启用/禁用延迟扩展和启用/禁用扩展选项。这就是 MS 决定实现该功能的方式。它不必是那样的。遗憾的是,如果没有 SETLOCAL/ENDLOCAL,您将无法控制这些状态。我经常希望我可以在不本地化环境的情况下启用或禁用延迟扩展。
我在编写批处理文件以根据命令行参数和一堆内部逻辑更改目录时遇到了这种行为。
使用 setlocal 和更改目录的一种方法是递归调用批处理文件,将目标路径作为字符串返回,并让顶级调用者cd访问它。
在此示例中,批处理文件在命令行上使用p或px更改到特定目录:
@echo off
if not "%1"=="recurse" (
for /f "delims=" %%i in ('%0 recurse %1') do cd %%i
exit /b
)
setlocal
rem Do things here with "local" variables
if "%2"=="p" (
echo "c:\program files"
) else if "%2"=="px" (
echo "c:\program files (x86)"
)
笔记:
感谢 SO Batch 相当于 Bash backticks。