文章修改自:
變數延遲在
for語句中起著至關重要的作用,不只是在
for語句中,在其他的復合語句中,它也在幕後默默地工作著.
例如,你編寫了這樣乙個**:
示例1:
@echo off
set num=0&&echo %num%
pause
你的本意是想對變數
num賦值之後,再把這個值顯示出來,結果,顯示出來的並不是
0,而是顯示:
echo
處於關閉狀態。
之所以會出錯,是因為
「變數延遲
」這個傢伙在作怪。
在講解變數延遲之前,我們需要了解一下
批處理的執行過程,它將有助於我們深入理解變數延遲。
批處理的執行過程是怎樣的呢?
「自上而下,逐條執行」.
「自上而下
」,這一條和我們本節的講解關係不大,暫時略過不說,後一條,
「逐條執行
」和變數延遲有著莫大的干係,它是我們本節要關注的重點。
很多人往往認為一行**就是一條語句,從而把
「逐條執行」與
「逐行執行
」等同起來,這就大錯特錯了。「逐條
」並不等同於「逐行
」。這個「條
」,是「一條完整的語句
」的意思,並不是指
「一行**」。在
批處理中,是不是一條完整的語句,並不是以行來論的,而是要看它的作用範圍。
什麼樣的語句才算
「一條完整的語句」呢?
1、在復合語句中,整個復合語句是一條完整的語句,而無論這個復合語句占用了多少行的位置。常見的復合語句有:
for語句、
if……else
語句、用連線符&、
||和&&連線的語句,用管道符號
|連線的語句,以及用括號括起來的、由多條語句組合而成的語句塊;
2、在非復合語句中,如果該語句佔據了一行的位置,則該行**為一條完整的語句。
例如:示例2
:@echo off
set num=0
for /f %%i in ('dir /a-d /b *.exe') do (
set /a num+=1
echo num
當前的值是
%num%
)echo
當前目錄下共有
%num%
個exe
檔案dir /a-d /b *.txt|findstr "test">nul&&(
echo
存在含有
test
字串的文字本件
)||echo
不存在含有
test
字串的文字檔案
if exist test.ini (
echo
存在test.ini
檔案) else
不存在test.ini
檔案pause
上面的**共有
14行,但是只有完整的語句只有
7條,它們分別是:第1
條:第1
行的echo
語句;第
2條:第2行的
set語句;第3
條:第3、4
、5、6
行上的for
復合語句;第4
條:第7
行的echo
語句;第
5條:第8、
9、10行上用&&和
||連線的復合語句;第6
條:第11、12
、13行上的if……else
復合語句;第7
條:第14
行上的pause
語句。在這裡,我之所以要花這麼長的篇幅來說明一行**並不見得就是一條語句,是因為
批處理的執行特點是「逐條
」執行而不是「逐行
」執行,澄清了這個誤解,將會更加理解
批處理的預處理機制。
在**「逐條」
執行的過程中,
cmd.exe
這個批處理
直譯器會對每條語句做一些預處理工作
,這就是
批處理中大名鼎鼎的
「預處理機制
」。預處理的大致情形是這樣的:
首先,把一條完整的語句讀入記憶體中(不管這條語句有多少行,它們都會被一起讀入),然後,識別出哪些部分是命令關鍵字,哪些是開關、哪些是引數,哪些是變數引用
……如果**語法有誤,則給出錯誤提示或退出
批處理環境;如果順利通過,接下來,就把該條語句中所有被引用的變數及變數兩邊的百分號,用這條語句被讀入記憶體之時就已經賦予該變數的具體值來替換
……當所有的預處理工作完成之後,
批處理才會執行每條完整語句內部每個命令的原有功能。也就是說,如果命令語句中含有變數引用(變數及緊鄰它左右的百分號對),並且某個變數的值在命令的執行過程中被改變了,即使該條語句內部的其他地方也用到了這個變數,也不會用最新的值去替換它們,因為某條語句在被預處理的時候,所有的變數引用都已經被替換成字串常量了,變數值在復合語句內部被改變,不會影響到語句內部的其他任何地方。
順便說一下,執行**示例
2之後,將在螢幕上顯示當前目錄下有多少個
exe檔案,是否存在含有
test
字串的文字檔案,以及是否存在
test.ini
這個檔案等資訊。讓很多人百思不得其解的是:如果當前目錄下存在
exe檔案,那麼,有多少個
exe檔案,螢幕上就會提示多少次
"num
當前的值是
0" ,而不是顯示1到
n(n是
exe檔案的個數)。
結合上面兩個例子,我們再來分析一下,為什麼這兩段**的執行結果和我們的期望有一些差距。
在示例1
中,set num=0&&echo %num%
是一條復合語句,它的含義是:把
0賦予變數
num,成功後,顯示變數
num的值。
雖然是在變數
num被賦值成功後才顯示變數
num的值,但是,因為這是一條復合語句,在預處理的時候,
&&後的
%num%
只能被set
語句之前的語句賦予變數
num的具體值來替換,而不能被復合語句內部、
&&之前的
set語句對
num所賦予的值來替換,可見,此
num非彼
num。可是,在這條復合語句之前,我們並沒有對變數
num賦值,所以,
&&之後的
%num%
是空值,相當於在
&&之後只執行了
echo
這一命令,所以,會顯示
echo
命令的當前狀態,而不是顯示變數
num的值(雖然該變數的值被
set語句改變了)。
在示例2
中,for
語句的含義是:列舉當前目錄下的
exe檔案,每發現乙個
exe檔案,變數
num的值就累加
1,並顯示變數
num的值。
看了對示例
1的分析之後,再來分析示例
2就不再那麼困難了:第3、
4、5行上的**共同構成了一條完整的
for語句,而語句
"echo num
當前的值是
%num%"
與"set /a num+=1"
同處復合語句
for的內部,那麼,第4行上
set改變了
num的值之後,並不能對第
5行上的變數
num有任何影響,因為在預處理階段,第
5行上的變數引用
%num%
已經被在
for之前就賦予變數
num的具體值替換掉了,它被替換成了
0(是被第
2行上的
set語句賦予的)。
如果想讓**示例
1的執行結果中顯示
&&之前賦予
num的值,讓**示例
2在列舉
exe檔案的時候,從1到
n地顯示
exe檔案的數量,那又該怎麼辦呢?
對**示例
1,可以把用
&&連線復合語句拆分為兩條單獨的語句,寫成:
@echo off
set num=0
echo %num%
pause
但是,這不是我們這次想要的結果。
對這兩段**都適用的辦法是:
使用變數延遲擴充套件語句,讓變數的擴充套件行為延遲一下,從而獲取我們想要的值。
變數延遲(上)
文章修改自 變數延遲在 for語句中起著至關重要的作用,不只是在 for語句中,在其他的復合語句中,它也在幕後默默地工作著.例如,你編寫了這樣乙個 示例1 echo off set num 0 echo num pause 你的本意是想對變數 num賦值之後,再把這個值顯示出來,結果,顯示出來的並不...
變數延遲(下)
在這裡,我們先來看看 變數擴充套件 有是怎麼一回事。用cn dos裡批處理達人willsort的原話,那就是 在許多可見的官方文件中,均將使用一對百分號閉合環境變數以完成對其值的替換行為稱之為 擴充套件 expansion 這其實是乙個第一方的概念,是從命令直譯器的角度進行稱謂的,而從我們使用者的角...
BAT 延遲變數
好東西,搞了很久才發現有這個東西。延遲環境變數在 bat裡是重中之重,雖然前面說過,熟練應用 for才算會寫批處理,但如果不懂延遲環境變數的話,那麼你就只能寫出簡單的批處理,而 for語句也不能發揮最大的作用。延遲環境變數在 cmd下預設是關閉的,如果要使用延遲環境變數,可以用以下兩種方法開啟 1....