为什么setlocal会干扰windows批处理文件中的chdir?

时间:2013-11-22 20:32:17

标签: batch-file chdir delayedvariableexpansion

如果我运行批处理文件

setlocal
chdir ..

目录未更改,但如果我运行

setlocal
endlocal 
chdir ..

它正常工作。这必须与setlocal完全一致。但是,当您阅读setlocal的定义时,并不完全明显,这与环境变量的显示方式有关。我希望这是一个很好的机会来解释setlocal实际上做了什么以及为什么它干扰了chdir。

2 个答案:

答案 0 :(得分:2)

SETLOCAL(help setlocalsetlocal /?)的帮助文档实际上很好地解释了这种情况。唯一不明显的是“ 环境变化的本地化 ”不仅包括环境变量,还包括当前目录,ECHO状态和延迟扩展和扩展状态。可能会有更多,但我现在想不到它。

实际上解释了绊倒你的事情:“ 当到达批处理脚本的末尾时,对该批处理脚本发出的任何未完成的SETLOCAL命令执行隐含的ENDLOCAL。 / em> “未说明对被调用的子程序也是如此。

当您的批处理脚本结束时,隐含的ENDLOCAL会“擦除”CHDIR的效果。您的第二个代码中的显式ENDLOCAL会使您返回到根环境,因此您的CHDIR将被保留。


更新

当前目录不是环境变量,即使您通常可以使用%CD%获取当前值。你可以通过SET CD证明它 - 它可能会给你“环境变量CD未定义”。如果使用set "CD=some value"显式定义自己的真实CD变量,则%CD%将返回您指定的值,而不是当前目录。

原始的SETLOCAL命令无法在旧的COMMAND.COM天中控制延迟扩展或扩展。引入CMD.EXE时添加了启用/禁用DelayedExpansion和启用/禁用扩展选项。这就是MS决定如何实现该功能。它不一定是这样的。在许多方面,如果没有SETLOCAL / ENDLOCAL,您将无法控制这些状态,这很不幸。我经常希望能在不本地化环境的情况下启用或禁用延迟扩展。

答案 1 :(得分:0)

我遇到了这种行为,编写批处理文件以根据命令行参数和一堆内部逻辑更改目录。

使用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)"
)

注意:

  • 我选择了字符串" recurse"任意。
  • delims 设置为空,因此它不会破坏路径中空格的返回字符串。
  • %0返回批处理文件的路径以进行递归。

感谢SO Batch equivalent of Bash backticks