2011-07-13 54 views
36

我的大多數腳本注意到,這兩個通常在同一行這樣:SETLOCAL和ENABLEDELAYEDEXPANSION如何工作?

SETLOCAL ENABLEDELAYEDEXPANSION 

是實際上兩個獨立的命令,並且可以在單獨的行寫?

將設置如果它被設置在腳本的第一線,直到劇本到底要不要禁用ENABLEDELAYEDEXPANSION對劇本產生不利影響?

+0

我通常把該行放在幾乎所有的我的腳本,它很少引起問題,我喜歡它更好地處理轉義字符,特別是在解析XML或HTML時。 – djangofan

+0

@djangofan你有沒有考慮過使用AutoIt進行這些任務?高度推薦它。我已經從AutoIt的batch/powershell/vbscript移開。 – Mechaflash

+2

是的,我聽說過它。也許我會仔細看看。我不喜歡要求第三方的東西,但似乎我不如使用Powershell,如果是這樣的話。 – djangofan

回答

15

ENABLEDELAYEDEXPANSION是傳遞給SETLOCAL命令中的參數(看setlocal /?

其效果住的腳本的持續時間,或一個ENDLOCAL

當批處理腳本的端部是達到一個隱含ENDLOCAL是,對於該批處理腳本 發佈的任何優秀SETLOCAL命令執行 。

特別地,這意味着,如果你在腳本中使用SETLOCAL ENABLEDELAYEDEXPANSIONany environment variable changes are lost at the end of it除非你take special measures

+6

第二部分的問題呢? – Mechaflash

+0

那麼它只會有一個不利的影響,如果你啓用它,然後寫了一些代碼行爲有所不同 –

+0

不可能,但是是真的。 – djangofan

8

ENABLEDELAYEDEXPANSION部分在某些使用延遲擴展的程序中是必需的,也就是說,它採用在IF或FOR命令中修改的變量的值,通過將它們的名稱放在感嘆號中。

如果啓用在不需要它的腳本這個擴展,腳本的行爲只是不同的,如果它包含括在感嘆號的標誌名字!喜歡! !這些!。通常情況下,名字只是刪除,但如果是偶然存在具有相同名稱的變量,那麼結果是不可預知的,取決於這樣的變量的值,並在它出現的地方。

SETLOCAL部分在一些專門的(遞歸)程序中是必需的,但是當您想要確保不偶然修改任何具有相同名稱的現有變量或者想要自動刪除所有您程序中使用的變量。但是,因爲沒有單獨的命令來啓用延遲擴展,所以需要此操作的程序還必須包含SETLOCAL部分。

+0

使用EnableDelayedExpansion,如果你的文本只包含一個'!'如'echo Hello!',並且在同一行中有一個感嘆號,那麼你也會遇到問題。' – jeb

81

我想你應該明白什麼延遲擴展。現有的答案沒有解釋它(充分)恕我直言。

鍵入SET /?解釋了事情相當不錯:

延遲環境變量擴充是獲取當前擴大其發生在 文本行被讀取的周圍 侷限性是有用的,而不是當它被執行。下面的示例 顯示了與即時變量擴展問題:

set VAR=before 
if "%VAR%" == "before" (
    set VAR=after 
    if "%VAR%" == "after" @echo If you see this, it worked 
) 

絕不會顯示該消息,因爲在這兩種IF語句 取代當第一IF語句被讀取,因爲它在邏輯上 包括%VAR% IF的主體,這是一個複合陳述。因此,複合陳述中的IF 確實比較「之前」與 「之後」,這將永遠不會相等。同樣,預計下面的例子 將不起作用:

set LIST= 
for %i in (*) do set LIST=%LIST% %i 
echo %LIST% 
的是,它不會建立文件列表在當前目錄下,

而是將只設置LIST變量找到的最後一個文件。 同樣,這是因爲當讀取FOR 語句時,%LIST%僅展開一次,並且此時LIST變量爲空。所以 ,我們真正執行的循環是:

for %i in (*) do set LIST= %i 

這個循環繼續將LIST到找到的最後一個文件。

延遲的環境變量擴展允許您使用不同的 字符(感嘆號)來擴展環境變量,執行時間爲 。如果延遲變量擴充被啓用,如預期上述 例子可以寫成如下的工作:

set VAR=before 
if "%VAR%" == "before" (
    set VAR=after 
    if "!VAR!" == "after" @echo If you see this, it worked 
) 

set LIST= 
for %i in (*) do set LIST=!LIST! %i 
echo %LIST% 

又如這個批處理文件:

@echo off 
setlocal enabledelayedexpansion 
set b=z1 
for %%a in (x1 y1) do (
set b=%%a 
echo !b:1=2! 
) 

這將打印x2y2:每1被替換爲2.

沒有setlocal enabledelayedexpansion,感嘆號就是這樣,所以它會回顯!b:1=2!兩次。

因爲當一個(塊)語句是正常環境變量擴大,擴大%b:1=2%使用值b具有循環之前:z2(但y2時未設置)。

+0

要清楚,如果在命令中沒有感嘆號,延遲擴展什麼也不做,對不對? –

+1

對!感嘆號確實有其他微妙的[效果](https://ss64.com/nt/delayedexpansion.html)。 –

0

經常存在一個真正的問題,因爲在批處理文件結束時,不會導出設置在裏面的任何變量。所以它不可能出口,這導致了我們的問題。因此,我只是設置註冊表總是使用延遲擴展(我不知道爲什麼它不是默認的,可能是速度或遺留兼容性問題。)

+3

多年來使用批處理文件時,我已經自動將該指令添加到每個em文件,並且永遠不會關閉它。我不會爲系統默認啓用它,因爲您永遠不知道系統運行的批處理腳本或其他公司的批處理腳本是否可能與它發生衝突。這是我們正在討論的Windows;) – Mechaflash