Batch file CD环境变量何时更新?
通常会发布使用批处理脚本中的Batch file CD环境变量何时更新?,batch-file,cmd,Batch File,Cmd,通常会发布使用批处理脚本中的CD环境变量获取当前工作目录的技巧。但是CD在调用另一个批处理文件时不会得到更新。然后,cd命令会回显另一批处理文件的新路径,但%cd%(或!cd!)不会更新。例如: @echo off cd %~dp0 echo in %0: CD=%CD% pause call X:\testcall.cmd 将其保存为C:\testcall.cmd和X:\testcall.cmd,然后运行C:\testcall.cmd。您应该看到CD的值没有改变。这似乎不依赖于调用;
CD
环境变量获取当前工作目录的技巧。但是CD
在调用另一个批处理文件时不会得到更新。然后,cd
命令会回显另一批处理文件的新路径,但%cd%
(或!cd!
)不会更新。例如:
@echo off
cd %~dp0
echo in %0: CD=%CD%
pause
call X:\testcall.cmd
将其保存为C:\testcall.cmd
和X:\testcall.cmd
,然后运行C:\testcall.cmd
。您应该看到CD
的值没有改变。这似乎不依赖于调用
;以下工程均不适用:
start /D <NEW_DIR> <OTHER_CMD_FILE>
start cmd /c <NEW_DIR>\<OTHER_CMD_FILE>
cmd /c <NEW_DIR>\<OTHER_CMD_FILE>
<NEW_DIR>\<OTHER_CMD_FILE>
cd %~dp0
pushd %~dp0
…假设cmd.exe仅在该变量尚未设置时设置
CD
。是否正确?诊断
您已经在某个点显式地设置了CD
变量。如果这样做,它将不再自动反映当前工作目录。要撤消此操作,请将其设置为空:
set CD=
然后它将再次开始工作
为什么会这样?自动CD变量是作为一项功能引入的。我想他们只是不想破坏已经使用这个可变名称的现有脚本。所以,如果您显式地设置它,CMD将假定您是有意这样做的
讨论
首先,如果父进程有一个显式设置的CD
变量,它将被子进程继承
另一方面,您不应该期望任何一个更新父进程的%CD%
值:
start /D <NEW_DIR> <OTHER_CMD_FILE>
start cmd /c <NEW_DIR>\<OTHER_CMD_FILE>
cmd /c <NEW_DIR>\<OTHER_CMD_FILE>
然后使用(例如)%SCRIPT\u DIR%\config.txt“
引用该目录中的文件
或者,如果希望依赖当前目录,请使用cd/d%~dp0
%cd%
是当前目录,而%~dp0
是当前运行脚本的目录(带有尾随“\”)
另外,不要设置环境。var称为CD
,因为它将覆盖默认的%CD%伪var,并且会令人难以置信地困惑-请参阅
例如,运行c:\temp\a.cmd时,即:
@echo off
echo Currently running script: %~dpnx0
cd %~dp0
echo scriptDir=%~dp0, CD=%CD%
cd %~dp0a
echo scriptDir=%~dp0, CD=%CD%
set CD=bogus value
echo scriptDir=%~dp0, CD=%CD%
输出:
Currently running script: c:\temp\a.cmd
scriptDir=c:\temp\, CD=c:\temp
scriptDir=c:\temp\, CD=c:\temp\a
scriptDir=c:\temp\, CD=bogus value
您可以将
%cd%
变量设置为您想要的任何值,C:
驱动器的真实当前目录存储在%=C:%
变量中,您不能使用set
命令更改此值:
@echo off
echo Currently running script: %~dpnx0
cd %~dp0
echo scriptDir=%~dp0, CD=%CD%
set CD=bogus value
echo scriptDir=%~dp0, CD=%CD%, =c:=%=c:%
set =c:=bogus value
echo scriptDir=%~dp0, CD=%CD%, =c:=%=c:%
输出为:
Currently running script: C:\OldDir\a.bat
scriptDir=C:\OldDir\, CD=bogus value
scriptDir=C:\OldDir\, CD=bogus value, =c:=C:\OldDir
syntax error.
scriptDir=C:\OldDir\, CD=bogus value, =c:=C:\OldDir
子进程的=C:
变量始终从父进程设置。如果在脚本中避免使用setlocal
命令或选择endlocal
,则可以更改当前cmd会话的当前目录:
C:\OldDir>type script.bat
cd c:\newdir
C:\OldDir>script
C:\OldDir>cd c:\newdir
C:\NewDir>
使用脚本目录
%~dp0
可以解决问题,但通常不是。这样做效果更好:
cd >tmpfile
set /P CD= <tmpfile
del tmpfile
cd>tmpfile
set/P CD=我根据您的评论构建了两个批处理文件
test1.bat-位于C:\temp
@echo off
cd %~dp0
echo File %~f CD=%CD%
call X:\test2.bat
test2.bat-位于*X:*
从C:\temp启动test1时,输出为
File C:\temp\test1.bat CD=C:\temp
File X:\test2.bat CD=C:\temp
结果绝对正确强>
以绝对或相对路径启动批处理文件(或任何其他程序)不会更改当前目录
CD似乎出现故障,因为CD无法更改驱动器的使用方式
您需要添加一个开关CD/d%~dp0
CD
未明确设置。当cmd最初设置时,它也将保持其值。关键可能是你所说的:CD
从未被M$真正实现过。因此,set CD=%~dp0
似乎是解决方案,因为CD
是一个标准变量,我发现一般来说,为同样的事情引入另一个变量会使问题变得复杂。当你在一个(更大的)脚本中看到像SCRIPT\u DIR
这样的变量时,你总是想知道它是如何设置的,在哪里设置的;对于CD
而言,其含义是固有的。@AndreasSpindler,您似乎认为工作目录和脚本目录是同一件事——它们根本不是同一件事。如果%CD%未反映当前工作目录,则表示它已由当前脚本、以前运行的另一个脚本或调用进程显式设置。另外,CD和SCRIPT_DIR(或%%dp0)的含义并不相同。SCRIPT_DIR或%dp0将是脚本文件的位置。CD是当前工作目录,可能不相同。@AndreasPindler:设置CD变量的值是一个非常糟糕的主意。想一想,如果有人试图设置日期或时间变量的值,会发生什么情况。你的想法的答案是:是的,所有这些变量都是同一类型的+1、好建议。但请注意,如果从UNC路径名(\\myserver\myshare\myfile.bat)运行批处理文件,则cd/d%~dp0将无法工作。改为使用pushd,它将为UNC路径创建一个临时驱动器号。@Aacine:SettingDATE
将不正确;但是不更新CD
,这难道不是一个bug吗?如果您看到代码中使用了CD
,您不希望它返回当前工作目录吗?至少开箱即用的行为是不可理解的;在批处理文件之间来回分支时,依赖CD
可能会很危险。%=c:
不包含真正的当前目录,它只包含驱动器c:的当前目录,%=d:%
包含驱动器d:的当前目录。所以你不知道哪个是真正的电流驱动是的,你完全正确。编辑了我的答案。每个卷都有自己的“当前目录”。如果设置了%=X:
目录,则无法重命名该目录。它是在第一次访问卷时设置的。在调用方批处理或被调用批处理中,在哪里回显%CD%
?如果使用set CD=…
显式设置CD
,则无法访问伪变量CD
C:\OldDir>type script.bat
setlocal
cd c:\newdir
C:\OldDir>script
C:\OldDir>setlocal
C:\OldDir>cd c:\newdir
C:\OldDir>
cd >tmpfile
set /P CD= <tmpfile
del tmpfile
@echo off
cd %~dp0
echo File %~f CD=%CD%
call X:\test2.bat
@echo off
cd %~dp0
echo File %~f CD=%CD%
File C:\temp\test1.bat CD=C:\temp
File X:\test2.bat CD=C:\temp