溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

dos環(huán)境變量延遲擴展enabledelayedexpansion是怎樣的

發(fā)布時間:2021-09-16 14:29:38 來源:億速云 閱讀:129 作者:柒染 欄目:開發(fā)技術

這期內容當中小編將會給大家?guī)碛嘘Pdos環(huán)境變量延遲擴展enabledelayedexpansion是怎樣的,文章內容豐富且以專業(yè)的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。

一,什么是延遲環(huán)境變量擴展?

延遲變量全稱"延遲環(huán)境變量擴展",要理解這個東西,我們還得先理解一下什么叫變量擴展!
  CMD在解釋我們的命令的時候,首先會讀取一條完整的命令,然后對其進行一些命令格式的匹配操作,看你所輸入的
命令格式是不是符合它的要求.如果我們要在命令中引用一些變量,那么我們如何讓CMD在解釋我們的命令時,能識別
出這個變量呢?這時我們就可以在變量名字兩邊加一個%號,如%name%.當CMD在讀取我們的整條命令進行格式匹配的時
候,就會發(fā)現(xiàn)name這個字符兩邊加了%號,就不會把它當作普通字符處理,而是會把它當作一個變量處理,變量名叫name

  然后CMD就會找到變量名對應的值,用該值替換掉這個變量名字(name),(如果變量名不存在值,就返回空值).再將這
個替換好并且匹配的命令執(zhí)行!這個替換值的過程,就叫做變量擴展,說白了就是把變量的名字,用它的值給替換掉后
執(zhí)行!也就是批處理如何識別一個變量的過程.(注意:這里只是變量的擴展的意思,不是延遲環(huán)境變量擴展,要理解延
遲環(huán)境變量擴展,必須先理解什么是變量的擴展) 也就是批處理如何識別一個變量的過程.

例1,

@echo off
set var=test
echo %var%
pause

  CMD在讀取到echo %var%這句命令后,就會進行匹配操作,它馬上就發(fā)現(xiàn)var字符兩邊有%號,這時CMD就會把它當作一
個變量處理,查看這個var變量名是不是有值,如果有就用該值把變量名var給替換掉,這里我們的var在上一條命令set
 var=test中,給var賦值為test,所以CMD會用test把%var%這個變量名替換掉,替換后的結果就為echo test了.這些步
驟都是CMD進行匹配操作的步驟,匹配完后,他再執(zhí)行echo test這條語句,這時我們的CMD中就會echo出一個test了.

  什么是環(huán)境變量擴展知道了,那什么是延遲環(huán)境變量擴展呢?

  在理解環(huán)境變量擴展時,我們知道CMD在解釋命令時,首先會把一條完整的命令進行讀取,然后進行匹配操作,匹配時
它會把命令里的變量用變量的值給替換掉,然后執(zhí)行這個替換好的命令.問題就出在"一條完整的命令",在BAT中,IF
FOR這樣的命令都可以加括號,將一些命令嵌套在里面執(zhí)行.這樣的話對于一條可以加擴號嵌其他命令的命令,他的完
整格式就是for %%i in (....)這樣一個整體.此時,如果我們如果在括號里面嵌入一些設置變量值的命令,就會出現(xiàn)
問題了!

例2,

@echo off
for /l %%i in (1,1,5) do (
  set var=%%i
  echo %var%
)
pause

執(zhí)行后會顯示5個空行的錯誤提示!為什么?根據(jù)我們上面說的知識來理解。

  通過這兩個例子,大家應該已經(jīng)理解,如果只有環(huán)境變量擴展這個過程的話,如果我們在可以嵌套命令的命令中執(zhí)行
賦值操作時,會讓我們的BAT出現(xiàn)給變量賦值的問題.那么這個時候"延遲環(huán)境變量擴展",這個概念就被提出來了。

  在批處理中,我們可以用setloacl enabledelayedexpansion 這個命令來啟用"延遲環(huán)境變量擴展" ,在我們啟用
了"延遲環(huán)境變量擴展"后,當CMD在解釋含有嵌套格式的命令時,他會把嵌套的命令一條一條的先執(zhí)行一次,然后再進
行匹配操作,這樣我們的賦值操作就會完成.并且在"延遲環(huán)境變量擴展"啟用后,CMD會用!號來判斷這是不是一個變量
。如沒啟用前變量用%name%這樣的格式判斷,啟用后就用!name!這樣的格式判斷了,這個符號我們需要注意!

例3,

@echo off
setlocal enabledelayedexpansion
set var=1
for /l %%i in (1,1,5) do (
  set /a var =%%i 
  echo !var!
)
pause

這樣大家應該明白什么是延遲環(huán)境變量擴展了吧.再來一個例子

例4,

@echo off
set var=test & echo %test%
pause

這條命令放在一行,表示他是一條完整的命令,不啟用"延遲環(huán)境變量擴展",就會出現(xiàn)上面的賦值錯誤!改成下這樣就
OK了:

@echo off
setlocal enabledelayedexpansion
set var=test & echo !var!
pause

二,批處理變量延遲詳解

  關于環(huán)境變量延遲擴展,使用set /?可以查看到部分說明,不過考慮到其粗劣的翻譯水平,建議在查看之前,首
先chcp 437切換為英文查看原英文說明。鑒于文中已說得十分詳盡,而且有數(shù)個代碼示例,應該不難理解。在此僅
略作一些補充。

  在許多可見的官方文檔中,均將使用一對百分號閉合環(huán)境變量以完成對其值的替換行為稱之為“擴展(expansion
)”,這其實是一個第一方的概念,是從命令解釋器的角度進行稱謂的,而從我們使用者的角度來看,則可以將它
看作是引用(Reference)、調用(Call)或者獲?。℅et)。

  而命令解釋器是擴展環(huán)境變量的行為大致如下:首先讀取命令行的一條完整語句,在進行一些先期的預處理之后
,命令被解釋執(zhí)行之前,會對其中用百分號閉合的字符串進行匹配,如果在環(huán)境空間中找到了與字符串相匹配的環(huán)
境變量,則用其值替換掉原字符串及百分號本身,如果未得到匹配,則用一個空串替換,這個過程就是環(huán)境變量的
“擴展”,它仍然屬于命令行的預處理范疇。

  而一條“完整的語句”,在NT的命令解釋器CMD中被解釋為“for if else”等含有語句塊的語句和用“& | && ||
”等連接起來的復合語句。
  因此,當CMD讀取for語句時,其后用一對圓擴號閉合的所有語句將一同讀取,并完成必要的預處理工作,這其中
就包括環(huán)境變量的擴展,所以在for中的所有語句執(zhí)行之前,所有的環(huán)境變量都已經(jīng)被替換為for之前所設定的值,
從而成為一個字符串常量,而不再是變量。無論在for中將那些環(huán)境變量如何修改,真正受到影響的只是環(huán)境變量空
間,而非for語句內部。

  而為了能夠在for語句內部感知環(huán)境變量的動態(tài)變化,CMD設計了延遲的環(huán)境變量擴展特性,也就是說,當CMD讀取
了一條完整的語句之后,它不會立即執(zhí)行變量的擴展行為,而會在某個單條語句執(zhí)行之前再進行擴展,也就是說,
這個擴展行為被“延遲”了。

  延遲環(huán)境變量擴展特性在CMD中缺省是關閉的,開啟它的方法目前有兩個:一是CMD /v:off(此處說法有誤,應為
 CMD /v:on——namejm 注),它會打開一個新的命令行外殼,在使用exit退出這個外殼之前,擴展特性始終有效,
常用于命令行環(huán)境中;二是setlocal EnableDelayedExpansion,它會使環(huán)境變量的修改限制到局部空間中,在
endlocal之后,擴展特性和之前對環(huán)境變量的修改將一同消失,常用于批處理語句中。


   上面是willsort寫的帖子對于新手來說比較難理解。不過沒關系,我們先分析一個例子,同樣是引用willsort老
大的。

本例啟用了變量延遲,是個正確的例子!

例1,

@echo off & setlocal EnableDelayedExpansion
for /f "tokens=* delims=" %%i in ("Hello world.") do (
  set n=%%i
  set n=!n:ld.=t!
  set n=!n:o w= S!
  set n=!n:He=Wi!
  echo !n!
)
Pause

將上面代碼保存為.bat雙擊執(zhí)行后會顯示“Will Sort”字符串,下面將講解每個語句的意思:

1.@echo off & setlocal EnableDelayedExpansion
關閉命令回顯,并啟用變量延遲

2.for /f  "tokens=* delims=" %%i in ("Hello world.") do (  )
for命令及其參數(shù)的使用,請大家在論壇里搜索相關字眼。限于篇幅問題,這里不作討論。如果此時你不明白它的意
思,那么你就當它的作用是把字符串“Hello world.”賦值給%%i好了,當然這只是權宜之計,以后一定要學習for
的使用!

3.set n=%%i
把%%i的值(即Hello world.)賦予給變量n,這個大家都知道吧

4.set n=!n:ld.=t!
這里要講講set替換字符的功能了。這個語句的意思是,先獲取變量n的值(此時n的值是“Hello world.”),然后
將字符“t”替換字符“l(fā)d.”,然后再將替換后的結果再次賦值給變量n(此時n的值變?yōu)椤癏ello wort”)。至于
set替換字符的編寫格式,大家可以在CMD鍵入“set/?”找到“%PATH:str1=str2%”這段有說明

5.set n=!n:o w= S!
意思和上句一樣,只是替換和被替換的內容不同。它是將“ S”替換“o w”(注意S前面和w前面都有個空格),其
實willsort老大是想證明set替換字符是支持句點和空格的(第4句“l(fā)d”后面有個.)。此時n的值為“Hell Sort”


6.set n=!n:He=Wi!
這句不用說了吧,執(zhí)行完這句后n的值為“Will Sort”

7.echo !n!
顯示變量n的值

需要注意的是,一旦啟用了變量延遲,就要用!號把變量括起來,而不能用%號。

  好了,每句的意思已經(jīng)說完了,下面要講本帖真正要討論的變量延遲的問題。
這里又要引用Will Sort老大的說明:當CMD讀取for語句時,其后用一對圓括號閉合的所有語句將一同讀取,并完成
必要的預處理工作,這其中就包括環(huán)境變量的擴展,所以在for中的所有語句執(zhí)行之前,所有的環(huán)境變量都已經(jīng)被替
換為for之前所設定的值,從而成為一個字符串常量,而不再是變量。

  而為了能夠在for語句內部感知環(huán)境變量的動態(tài)變化,CMD設計了延遲的環(huán)境變量擴展特性,也就是說,當CMD讀取
了一條完整的語句之后,它不會立即執(zhí)行變量的擴展行為,而會在某個單條語句執(zhí)行之前再進行擴展,也就是說,這
個擴展行為被“延遲”了。

  總的來說是,在沒有啟用變量延遲的情況下,凡是在括號內(即do里面)的變量,在執(zhí)行for語句之前,就已經(jīng)被
替換成for語句之前其它命令對該變量所賦予的值。這句話不懂沒關系,下面再看一個例子,看完你就會明白。

例2,

@echo off
for /f "tokens=* delims=" %%i in ("Hello world.") do (
set n=%%i
set n=%n:ld.=t%
set n=%n:o w= S%
  set n=%n:He=Wi%
  echo %n% 
)
Pause

  這和前面的例子差不多,只是所有!號都換成%號,這是個錯誤的例子。因為它沒有啟用變量延遲,也沒有使用!
號把變量括起來。我們看到它的執(zhí)行結果是顯示“ECHO 處于關閉狀態(tài)”。
為什么會這樣呢?原因是,在沒有啟用變量延遲的情況下,凡是在括號內(即do里面)的變量,在執(zhí)行for語句之前
,就已經(jīng)被替換成for語句之前其它命令對該變量所賦予的值。

則是說在本例中的以下幾句

set n=%%i
set n=%n:ld.=t%
set n=%n:o w= S%
set n=%n:He=Wi%
echo %n%

  第一句能正常執(zhí)行并達到它的目的,因為它只是單純地將%%i的值賦予給變量n,所以沒有任何問題。其它幾句屬
這樣情況:早在for語句執(zhí)行前,CMD就急不切待地將這幾句里面的所有變量n一同執(zhí)行替換行為,替換為for之前,
其它命令對n所設置的值,從而使n變成一個常量。但在本例中,for語句之前只有@echo off這句,并沒有其它命令
對n作過任何賦值行為,所以在for之前,變量n的值為空值。
  即是說,set n=%n:ld.=t% 這句里面的變量n,在CMD讀?。ㄗ⒁馐亲x取不是執(zhí)行)完整個for語句后(這時還未輪
到set執(zhí)行自己的任務),就立刻被替換為一個空值,一個空值里面沒有任何東西,所以就不存在一字符替換另一字
符這種說法(沒有東西怎么替換?)。最終到執(zhí)行set n=%n:ld.=t%語句時,它只是獲取一個空值,再給變量n賦予
空值而已。其它幾句也是一樣原理。

  所以,最后echo %n%的時候變量n還是個空值,而echo命令沒有東西可以顯示,就只有顯示“ECHO 處于關閉狀態(tài)
”這句來說明自己的狀態(tài)

通過這個例子的說明,相信大家已經(jīng)知道變量延遲的作用吧!我們再回頭來看看例1。

啟用變量延遲后,在執(zhí)行

set n=!n:ld.=t!
set n=!n:o w= S!
set n=!n:He=Wi!
echo !n!

這些語句前,它們里面的變量n不會馬上被CMD替換(啟用延遲后,CMD變得有耐性啦^_^),而未被替換的話,那么n
就還是變量,而不是常量。等到執(zhí)行set n=!n:ld.=t!等這幾句時,變量n才被替換。這樣每個set命令都能感知變量
n的任何變化,從而作出正確的替換行為。這就是變量延遲啦!

不要以為只有for才要用變量延遲,下面這個例子同樣需要

例3,這是個錯誤的例子

@echo off
set mm=girl&echo %mm%
pause

執(zhí)行后依然顯示“ECHO 處于關閉狀態(tài)”。

  原因是沒有啟用延遲,而且在set mm=girl&echo %mm%語句前沒有其它命令對mm進行賦值。這時當CMD執(zhí)行set
mm=girl&echo %mm%語句前,就已經(jīng)急不切待地把變量mm的值替換了,而又因為前面沒給mm賦值,所以mm被替換為空
值,變成常量。等到echo命令執(zhí)行時,它其實是echo一個不會變化的常量,本例中即是空值。

有人會問,echo前面不是給mm賦值了嗎?
這個就要關系到CMD解釋命令的步驟,大家可以參詳本帖開頭willsort的帖子。

  總的來說是,如果不啟用變量延遲,在本例中,echo是不會理會也不會知道,它前面(指同一行語句)是否有其
它命令給mm賦值。它只會從set mm=girl&echo %mm%這句以上的語句中獲取它所要顯示的變量的內容,也就是說,上
一行或上幾行的命令將mm設置成什么值,echo命令就顯示什么值。

大家這樣做就明白了:

@echo off
set mm=boy
set mm=girl&echo %mm%
pause

看看顯示什么結果就知道了!

這樣編寫例3才正確:

@echo off&setlocal EnableDelayedExpansion
set mm=girl&echo !mm!
pause

開啟了變量延遲,變量擴展(替換)的行為就推遲到echo命令執(zhí)行時,這時echo能感知它前面的命令(本例的set)
對變量mm做了什么“壞事”,從而作出正確的判斷并執(zhí)行

三,批處理延遲變量(通俗解釋)

  變量延遲  setlocal EnableDelayedExpansion
  一個讓大多數(shù)新手頭痛的問題,網(wǎng)上教程雖多,但多半都是看不懂的,里面的專業(yè)術語太多。
以 cn-dos 聯(lián)盟的willsort的這篇教程為例,(個人認為是解釋的極具權威和專業(yè)的)

  但可能就是因為專業(yè),所以才看不懂,因為學cmd批處理的并不一定都是學計算機專業(yè)的。這個鬼東西確實不太好
理解,在下也是摸爬滾打多時,總結出一點點經(jīng)驗,現(xiàn)用通俗的方法解釋出來,希望能給新手些幫助,老鳥們見笑
了,若有不對的地方,歡迎指出。

  言歸正傳
在什么時候需要延遲變量,和該如何引用延遲變量,我想這才是大多數(shù)新手迫切想要知道的問題。
耐心看完下面的內容,我想對你應該是有幫助的。

  要想了解延遲變量,首先你要明白什么是“復合語句”好像又來了個“專業(yè)”名詞,別急,這個超好理解。所謂
“復合語句”就是指一對()里的所有命令。比如for的do后面
如:

for /f "delims=" %%i in (a.txt) do (
   set var=%%i
   echo %%i
   set num=%%i
)

這里do后面的三句命令,在一對()里面,這就叫“復合語句”,當然不止for 還有if 等等。。。
如:

if "%var%"=="abc" (
  echo ok
  set lis=123
)

反正就是凡是()里的所有命令,就叫“復合語句”
另外:這也是復合語句 set abc=123&echo %abc% 沒錯,通過管道命令&連接起來的命令,也是復合語句。

  好,了解了復合語句,現(xiàn)在開始講延遲變量,也就說,在復合語句中才要使用延遲變量。
我們先不去理解什么叫“變量的擴展”這玩意叫法太專業(yè),我到現(xiàn)在都不太明白,

  我們只要知道在什么時候需要使用延遲變量,如何才能正確提取到我們需要的變量就可以了,這才是我們的目的。
cmd在處理“復合語句”的時候,如果“復合語句”中用到了變量,會把變量的值當作復合語句之前變量的值來引用
。如果在此之前變量沒有被賦值,就把它當成空值。

例1,

@echo off
for /l %%i in (1 1 10) do (
  set var=%%i
  echo %var%
)
Pause

運行上面的代碼,顯示什么?顯示10個echo處于關閉狀態(tài)。按照邏輯,var的值應該依次是 1、2、3........10 才
對??!

這就是因為沒有開啟 延遲變量 的緣故,cmd把var的值當作復合語句之前的值來引用,
而在本例中,復合語句之前并沒有給var定義,所以var的值是空的,所以會顯示10個echo處于關閉狀態(tài)。

例2,

@echo off
set var=abc
for /l %%i in (1 1 10) do (
  set var=%%i
  echo %var%
)
Pause

運行上面的代碼,會顯示什么,大家應該知道了吧?

例3,

@echo off
set var=abc
for /l %%i in (1 1 5) do (
  set var%%i=%%i
  echo %var%
)
echo %var1% %var2% %var3% %var4% %var5%
pause

運行上面的代碼后,復合語句中所賦的值全部顯示出來了,這說明什么呢?

說明,在復合語句中,并不是沒有給變量賦值,只是你若沒有開啟延遲變量,你就沒法在復合語句中提取到它,要
等復合語句運行完畢后,才能提取到。

變量的表示方法:兩種:  1、%var%   2、!var!
第一種表示方法,大家都知道,第二種就是引用 延遲的變量。
在開啟了延遲變量的情況下,如果在復合語句之外,用哪種方法表示都可以。但是你若要在復合語句中引用復合語
句即時得到的變量,就要用第二種方法??蠢?/p>

例4,

@echo off
setlocal EnableDelayedExpansion
set var=abc
for /l %%i in (1 1 10) do (
  set var=%%i
  echo %var%
  echo !var!
)
Pause

注意:例子中有兩個echo 一個是顯示 %var% 一個是顯示 !var!
結果很明白了,%var% 顯示的結果是復合語句之前變量var的值,而 !var! 顯示的就是復合語句中即時得到的值。

例5,

@echo off
setlocal EnableDelayedExpansion
for /l %%i in (1 1 5) do (
  set var%%i=%%i
)
echo %var1% %var2% %var3% %var4% %var5%
echo !var1! !var2! !var3! !var4! !var5!
pause

這個例子說明什么,不用再解釋了吧?
說明在開啟了延遲變量的情況下,且在復合語句之外,用兩種方法都可以表示變量。就說到這吧。以上的解釋,完
全是出于個人的理解,也是為方便非專業(yè)人士理解,解釋肯定有錯誤的地方、就象學習英語時,為方便記憶,用漢
字的讀音來作解釋一樣。呵呵,是一種“偏門”各位新手千萬不要把以上所說的當成是“真理”,否則就變成是“
誤人”了。


四,什么時候使用延遲變量?如何使用?

  什么時候使用延遲變量?如何使用?這些一直是使新手困惑的地方,那到底是怎么樣的呢?那請看下面的例子,
我們將一步步引導大家。

例1,

@echo off
set /a num=0
for /l %%i in (1 1 3) do (
   Rem ================================
   set /a num =1 
   Rem 原意是變量num的值每次都加1
   Rem ================================
   echo %num%
)
pause>nul

  先猜猜看,運行之后的結果是什么呢?你是不是認為它會顯示:1 2 3 呢?我想大部分人會這么認為。你再將以
上代碼保存為批處理文件,運行,看看結果。
你會看到,顯示的結果并不是意料中的 1 2 3 而是 0 0 0,這個是為什么呢?

  原來這個是因為,批處理在處理for 或者if 語句中的變量時,先要進行預處理,把其中的用%%括起來的變量,先
替換為語句之前的變量(如上面的代碼,for語句中的%num%早就被替換為語句前的 值:0),所以,for語句運行時
,雖然已經(jīng)給變量加了1,但是,值卻不變(因為echo %num%中的%num%早已被替換為:0了)。
那么,要實現(xiàn)(for或者if)語句中的變量實時的變化(如這里,我就要將1 2 3 顯示出來)要怎么辦呢?那就要起
用延遲變量,先在批處理中申明:setlocal enabledelayedexpansion 然后,將語句:echo %num%改成!num!(也就
是將“%”改成“!”),這樣就可以達到效果了,演示代碼:

例2,

@echo off 
Rem ''''///////下面先申明起用延遲變量/////////////
setlocal enabledelayedexpansion
set /a num=0
for /l %%i in (1 1 3) do (
   Rem ================================
   set /a num =1 
   Rem 變量num的值每次都加1
   Rem ================================
   Rem '''''''//////////////////下面的變量不能再用"%"括起來,而應該用"!"////////////
   echo !num!
)
pause>nul


歸納總結:
1、為什么要用延遲變量?
讓if語句和for語句中的變量實時變化;

2、什么時候用延遲變量?
一般是用在 for 語句和 if 語句中;

3、怎么用延遲變量?
先在批處理中申明起用延遲變量:setlocal enabledelayedexpansion
然后將 for 語句、if語句中的變量用兩個"!"括起來即可

4、其實在使用變量嵌套變量也可以使用變量延遲的。

例3,

@echo off
set a=1
set b1=10
echo %b%a%%
pause

執(zhí)行顯示,得到 %b1%

其實我想得到的是 賦予b1的值,即 10  那么如何實現(xiàn)呢?將上例修改如下,

例4,

@echo off
set a=1&set b1=10
call,echo %%b%a%%%
pause>nul

call 這里實際是對命令行進行重新組織擴展,先擴展%%b%a%%%里面的%a%,使%a%變成a的值1,再用cal來擴展%b1%
。

也可以用變量延遲來實現(xiàn),方法如下:

例5,

@echo off
set /a a=1,b1=10
Setlocal EnableDelayedExpansion
echo:!b%a%! ...
pause


call 在這里的用法實際是變量延遲的一種快捷方式,變量延遲一般用在for的循環(huán)體里面。
call,%%b%a%%% 這里的逗號實際是一個分隔符,和空格一樣,還有很多分隔符可用,比如上例中的 echo:!b%a%! ,
當然并不是所有的命令都可以這樣用,看情況而定……


例6,

@echo off&setlocal enabledelayedexpansion
set a=1000
set b=dd
set a%b%=9000
set c=!a%b%! 
echo %c%
pause

執(zhí)行一下,看看顯示的將是什么?為什么是這樣?相信通過例4,例5你也能分析得出來吧?

上述就是小編為大家分享的dos環(huán)境變量延遲擴展enabledelayedexpansion是怎樣的了,如果剛好有類似的疑惑,不妨參照上述分析進行理解。如果想知道更多相關知識,歡迎關注億速云行業(yè)資訊頻道。

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權內容。

dos
AI