2013-04-29 158 views
2

通常會發布tipp以使用批處理腳本中的CD環境變量來獲取當前工作目錄。但CD將不會更新時call另一個批處理文件。然後cd命令回顯另一批文件的新路徑,但%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.EXECD只有當這個變量尚未取消設置。真正?

+0

你在哪裏調用方批次或稱爲批處理呼應'%CD%'? – jeb 2013-04-29 16:39:00

+0

如果你用'set CD = ...'明確設置'CD',你不能訪問僞變量'CD' – jeb 2013-05-07 10:11:31

+0

你不應該將你的例子保存爲_c:\ testcall.cmd_和_X:\ testcall。 cmd_,因爲_X:\ testcall.cmd_會以無限循環結束 – jeb 2013-05-08 09:50:16

回答

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% 

開始TEST1它從C:\溫度,輸出是

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

的結果是絕對正確的!

使用絕對或相對路徑啓動批處理文件(或任何其他程序)不會更改當前目錄。

CD似乎失敗,因爲CD不能更改驅動器你用它的方式。

您需要添加交換機CD /d %~dp0

+0

不混合......也許我的簡短例子不完整。正如我在最初的問題中所寫的,'cd%〜dp0','pushd'或'start/D'也不會更新'CD'。你可以在測試腳本的頂部加上'cd%〜dp0'來測試。獲得真實工作目錄的唯一方法似乎是在腳本的頂部調用'cd',並明確設置'CD'。但是這看起來像一個黑客 - 因此這個線程。 – 2013-05-08 10:00:38

+0

好的,但現在它變得清晰。 'CD'不會改變你的目錄沒有'/ D'開關 – jeb 2013-05-08 10:18:27

+0

有趣的......只有'cd/D'確實更新'CD'。我通過調用不同驅動器上的腳本和同一驅動器上的另一個目錄來測試它。在這兩種情況下,只有'cd/D'更新'CD'。很明顯,這是微軟打算的:通過添加'/ D',他們不想打破現有的只有在未設置時才設置'CD'的行爲。 **所以這是解決方案。** – 2013-05-08 11:19:41

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

+0

'CD'沒有明確設置。最初由_cmd_設置時,它也會保持其值。關鍵可能是你說的:'CD'從來沒有真正由M $實現。因此,設置CD =%〜dp0似乎是解決方案,因爲'CD'是一個標準變量,我發現它通常會引入另一個變量用於同一事物。當你在(更大的)腳本中看到像'SCRIPT_DIR'這樣的變量時,你總是想知道它是如何以及在哪裏設置的;對於CD而言,其含義是固有的。 – 2013-04-29 12:44:10

+0

@AndreasSpindler,你似乎認爲WORKING目錄和SCRIPT目錄是一回事 - 它們根本不是一回事。如果%CD%不能反映當前的WORKING目錄,則表示它已經被當前腳本或先前運行的另一個腳本或調用過程顯式設置。另外,CD和SCRIPT_DIR(或%〜dp0)並不意味着同樣的事情。 SCRIPT_DIR或%〜dp0將是腳本文件的位置。 CD是當前的工作目錄,可能不一樣。 – Ben 2013-04-29 13:25:39

+0

@AndreasSpindler:設置CD變量的值是一個非常糟糕的主意。想一想如果有人試圖設置DATE或TIME變量的值,會發生什麼。你的想法的答案是:是的,所有這些變量都是相同的類型! – Aacini 2013-04-29 16:04:35

6

%CD%當前目錄,而%~dp0是當前運行的腳本的目錄(尾隨「\」)。

另外,不要設置env。 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 
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,你可以改變persistend當前目錄爲當前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> 
+2

'%= c:'不包含*實際當前目錄*,它僅包含驅動器C的當前目錄:'%= d:%'包含驅動器D:的當前目錄。所以你不知道哪個是* real *當前驅動器 – jeb 2013-04-29 16:36:44

+0

是的,你是完全正確的。編輯我的答案。每卷都有自己的「當前目錄」。如果已設置,則無法重命名'%= X:'目錄。它在卷的第一次訪問時設置。 – Endoro 2013-04-29 17:10:30

0

使用腳本目錄%~dp0可以是一個解決方案,但通常不是。這效果更好:

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

此解決方案與CD變量一致。 CDcontains the current directory,如果它不在當前驅動器的根目錄中,則不以斜槓字符結尾。由cd打印的路徑行爲如此。

我使用這個好幾年了,沒有明確設置CD的問題。後來我開始使用PWD(如在Bash中)。 MSDOS中未保留此變量。所以我的問題實際上是:「我們可以擺脫這些線,還是這是一些MSDOS成語?「

有些人還寫,設置CD明確是不好麼MSODS從來沒有設計正確,而且沒有進一步發展任何你可以用它做是合法的有沒有不好的MSDOS編程 - 。?。剛剛好和壞的黑客我知道,沒有其他的語言,其中這個角度來說是合法的,這樣的程度

+0

這不是必需的,'CD'變量總是包含正確的目錄。有時你不能通過塊中的'%CD%'來訪問它,但這不是'CD'本身的問題。 – jeb 2013-05-07 08:45:14

+0

你真的看過這個帖子嗎?如果你來回調用批處理腳本,它不會被正確更新。 – 2013-05-07 09:08:13

+1

請在其中出現失敗的一個或兩個批處理文件的示例。我無法重現您的問題 – jeb 2013-05-07 10:09:32