2014-10-07 91 views
5

我試圖在批處理腳本中一起使用setlocal enabledelayedexpansioncd,這似乎不會將更改保留回shell。SETLOCAL ENABLEDELAYEDEXPANSION導致CD和PUSHD不會持續

我需要setlocal enabledelayedexpansion的原因是我需要腳本中的變量在腳本運行時動態擴展。

考慮以下樣本批處理文件:

a.bat 
================================ 
setlocal enabledelayedexpansion 
cd .. 

預期上述批處理文件不遷移到以前的目錄!

檢查this

+0

是什麼讓你說它不工作?你能描述一下你的實際問題嗎? – 2014-10-07 22:25:01

+0

引用提到PUSHD的主題標題,我同意CD不會持續,但pushd仍然存在,不是嗎?剛剛測試;批處理完成後,我確實從命令行彈出。 (甚至一對POPD每個工作) – MicrosoftShouldBeKickedInNuts 2017-12-21 18:53:32

回答

4

問題是setlocal導致當前目錄更改爲批處理文件本地。

setlocal /?

開始的環境更改的本地化批處理文件。 環境 發出SETLOCAL後所做的更改對批處理文件是本地的。 必須發出ENDLOCAL才能恢復以前的設置。當達到批處理腳本的末尾 時,將爲該批處理腳本發出的任何未完成的SETLOCAL命令執行隱含的ENDLOCAL。

當前目錄包含在「環境變化」中。

請嘗試此操作,請注意,它在批處理中響應C:\%CD%,但當批處理退出時,當前目錄仍會重置。

[11:42:00.17] C:\temp 
> cat test.bat 
@echo off 
setlocal enabledelayedexpansion 
cd .. 
echo %CD% 
[11:42:19.38] C:\temp 
> test.bat 
C:\ 

[11:42:23.00] C:\temp 
> 
+1

謝謝我更好地理解這一點!那麼當我需要setlocal以便動態擴展變量時,是否有任何方法可以獲得光盤以外的持久更改? – 2014-10-07 22:47:58

+0

你可以嘗試明確地調用'endlocal',然後*然後*改變目錄 - 或者在調用'setlocal'之前改變它。 – Blorgbeard 2014-10-07 22:51:05

+0

聽起來很完美!再次感謝:) – 2014-10-07 22:51:58

0

這是證明它的工作原理 - 在根目錄之上的任何文件夾中啓動批處理文件。

@echo off 
setlocal enabledelayedexpansion 
echo "%cd%" 
cd .. 
echo "%cd%" 
pause 
5

Blorgbeard提供了一個解釋,爲什麼CD SETLOCAL之後發出ENDLOCAL後不會保留(可以是明確的或隱含的)。

這是一個有趣的解決方法。 PUSHD堆棧與SETLOCAL/ENDLOCAL保存/恢復的環境無關。所以下面簡單序列將保留目錄的變化:

@echo off 
setlocal 
cd somePath 
pushd . 
endlocal 
popd 

不是非常有用的,如果somePath是不變的 - 你可以很容易地發出ENDLOCAL後的CD。但如果somePath是動態的,它可能非常有用。

+0

這是一個有趣的工作! – 2014-10-08 14:08:05

+0

非常好,我們可以用這個來傳遞一個字符串到ENDLOCAL嗎? – mosh 2017-07-27 15:51:05

+0

@mosh - 當然,但只有當字符串是用戶有權訪問的有效規範文件夾路徑。這對我來說似乎不是很有用。我想你可以在「標準」位置創建一個與你的字符串值相同的臨時文件夾。然後,您可以提取您的字符串值並刪除該文件夾。但是這對於可以使用哪些字符會有很大的限制。 – dbenham 2017-07-27 17:02:58

0

通過endlocal在註冊表中保存字符串。在win7 cmd上測試(skip = 2,可能與reg的不同版本有所不同。exe文件)

:: What: stash string in registry from cmd line, across endlocal barrier 
:: PS. I added %RANDOM% to Windows-NT and Win95 command.com and still using it. 
@echo off 

set key="HKCU\Volatile Environment" 
set keyname=stash%RANDOM% 
set keytype=REG_SZ 

setlocal ENABLEDELAYEDEXPANSION 

::== Save string 
set data_stash=Hello-%DATE%-%TIME% 
echo Saving=%data_stash% in key=%keyname% 
reg add %key% /v %keyname% /t %keytype% /d "%data_stash%" /f 

endlocal 

::== Read string 
echo reg query %key% /v %keyname% 
for /f "tokens=2* skip=2" %%a in ('reg query %key% /v %keyname%') do (
    set data_unstashed=%%b 
) 
echo Read data_unstashed=%data_unstashed% 

::== Delete stash 
reg delete %key% /v %keyname% /f 

編輯斯蒂芬 另一種方式來保存變量超出endlocal

@echo off 
set var1=hello 
set var2=world 
setlocal 
echo previous: %var1%, %var2% 
set var1=HELLO 
set var2=WORLD 
echo inside: %var1%, %var2% 
endlocal & set "var1=%var1%" & set "var2=%var2%" 
echo after: %var1%, %var2% 

的訣竅是,由於解析變量擴大之前endlocal是有效的,但set在之後結果爲
(抱歉劫持你的答案,但這對於評論來說也太大了)