CD环境变量何时更新?

时间:2013-04-29 11:54:09

标签: batch-file cmd

通常会发布使用批处理脚本中的CD环境变量来获取当前工作目录的tipp。但CD另一个批处理文件时,call将不会更新。然后cd命令回显另一个批处理文件的新路径,但%CD%(或!CD!)未更新。例如:

@echo off
 cd %~dp0
 echo in %0: CD=%CD%
 pause
 call X:\testcall.cmd

将其另存为C:\testcall.cmdX:\testcall.cmd,然后运行C:\testcall.cmd。您应该看到CD的值没有改变。这似乎不依赖call;以下都不起作用:

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

CD将保留旧值,而cd(命令)显示正确的目录。因此,我在脚本的开头设置了CD

set CD=%~dp0

...虽然假设 cmd.exe 仅在未设置此变量时才设置CD。真?

5 个答案:

答案 0 :(得分:6)

%CD%当前目录,而%~dp0是当前正在运行的脚本的目录(尾随'\')。

另外,不要设置环境。 var名为CD,因为它将覆盖默认的%CD%pseudo-var,并且会令人难以置信地混淆 - 请参阅OldNewThing - ERRORLEVEL is not %ERRORLEVEL%

例如,运行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

答案 1 :(得分:4)

<强>诊断

您在某些时候明确设置了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>

这些都创建了新进程,然后新进程会更改自己的工作目录。您不应期望这会影响父进程。

最后一个,根本不更新工作目录,除非OTHER_CMD_FILE执行CD命令:

<NEW_DIR>\<OTHER_CMD_FILE>

仅仅因为你在另一个目录中执行了一个脚本并不意味着脚本的工作目录会改变。 脚本工作目录不必设置为脚本的位置。

<强>建议

依赖于特定设置的工作目录通常是一个坏主意。

你可能想要这样的东西:

SET SCRIPT_DIR=%~dp0

然后使用(例如)"%SCRIPT_DIR%\config.txt"来引用该目录中的文件。

或者,如果您希望依赖当前目录,请使用cd /d %~dp0

答案 2 :(得分:2)

您可以将%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>

C:\OldDir>type script.bat
setlocal
cd c:\newdir

C:\OldDir>script

C:\OldDir>setlocal

C:\OldDir>cd c:\newdir

C:\OldDir>

答案 3 :(得分:1)

我从您的评论中构建了两个批处理文件

test1.bat - 位于 C:\ temp

@echo off
cd %~dp0
echo File %~f CD=%CD%
call X:\test2.bat

test2.bat - 位于* X:*

@echo off
cd %~dp0
echo File %~f CD=%CD%

C:\ temp 开始 test1 ,输出为

File C:\temp\test1.bat CD=C:\temp 
File X:\test2.bat CD=C:\temp

结果绝对正确!

使用绝对路径或相对路径启动批处理文件(或任何其他程序)不会更改当前目录。

CD 似乎失败,因为 CD 无法像您使用它一样更改驱动器。

您需要添加一个开关 CD /d %~dp0

答案 4 :(得分:0)

使用脚本目录%~dp0可以是一种解决方案,但通常不是。这样做效果更好:

cd >tmpfile
set /P CD= <tmpfile
del tmpfile

此解决方案与CD变量一致。 CD contains the current directory,如果它不在当前驱动器的根目录中,则不以斜杠字符结尾。由cd打印的路径完全如此。

我正在使用它多年,并且没有明确设置CD的问题。后来我开始使用PWD(如在Bash中)。 MSDOS中不保留此变量。所以我的问题实际上是:“我们可以摆脱这些界限,还是这些MSDOS成语?”

有些人写道明确设置CD是不好的。为什么? MSODS从未正确设计,也没有进一步开发。你能用它做的任何事都是合法的。没有糟糕的MSDOS编程 - 只是好的和坏的黑客。我不知道这种观点在某种程度上是合法的。