變數延遲(上)

2021-06-02 09:12:27 字數 4277 閱讀 9002

文章修改自:

變數延遲在

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....