大綱php
一 前言 二 for語句的基本用法 三 for /f (delims、tokens、skip、eol、userbackq、變量延遲) 四 for /r (遞歸遍歷) 五 for /d (遍歷目錄) 六 for /l (計數循環)
1、前言html
在批處理中,for是最爲強大的命令語句,它的出現,使得解析文本內容、遍歷文件路徑、數值遞增/遞減等操做成爲可能;配合if、call、goto等流程控制語句,更是能夠實現腳本複雜的自動化、智能化操做;合理使用for語句,還能使代碼大爲簡化,免除各位編寫大量重複語句之苦。而可否熟練使用for語句,已經成爲衡量一我的批處理水平高低最主要的標準。數據庫
在這個系列教程中,我將經過實際應用中頻繁出現的例子,帶領你們步入for語句的神奇之門,一步步邁向for語句的魔幻殿堂,使得你們在實際的應用中,能獨立寫出簡潔高效的代碼,在批處理的世界裏自由馳騁。編程
注意:如下的講解,都是基於簡體中文版Windows XP Pro SP3的操做系統環境。windows
2、for語句的基本用法數組
正如色彩繽紛的七彩光芒是由紅綠藍三原色構成的同樣,最複雜的for語句,也有其基本形態,它的模樣是這樣的:oop
在cmd窗口中:學習
FOR %variable IN (set) DO command [command-parameters]
在批處理文件中:測試
FOR %%variable IN (set) DO command [command-parameters]
具體例子:spa
For %i in (1 2 3) do @echo %i
之因此要區分cmd窗口和批處理文件兩種環境,是由於在這兩種環境下,命令語句表現出來的行爲雖然基本同樣,可是在細節上仍是稍有不一樣。
最明顯的一個差別就是:在cmd窗口中,for以後的形式變量I必須使用單百分號引用,即%i;而在批處理文件中,引用形式變量i必須使用雙百分號,即%%i。
爲了方便起見,若不是特別強調,如下的講解都以批處理文件環境爲例。
咱們先來看一下for語句的基本要素都有些什麼:
一、for、in和do是for語句的關鍵字,它們三個缺一不可;
二、%%I是for語句中對形式變量的引用,就算它在do後的語句中沒有參與語句的執行,也是必須出現的;
三、in以後,do以前的括號不能省略;
四、command1表示字符串或變量,command2表示字符串、變量或命令語句;
如今,你可能已經會寫一個簡單的for語句了,好比:
[code1]
@echo off for %%I in (bbs.bathome.net) do echo %%I pause
保存爲批處理文件並執行,將會在彈出的批處理窗口中看到這樣的信息:
bbs.bathome.net 請按任意鍵繼續...
很快地,你會以爲這個for語句是如此的簡單,簡單到你絲毫感覺不出它的強大:這個for語句,和我直接用echo語句沒什麼兩樣啊!
是的,演示代碼永遠都只是演示而已,就像大多數高級語言的教科書同樣,在引導新手學習的時候,基本上都是千篇一概地告訴你們如何編寫一個能顯示 hello world! 的窗口,從這些演示代碼中,你看不到它們具備多少實用性,你只是感到有點好奇:咦,竟然彈出了一個窗口?片刻以後,你就會以爲索然無味。
那好吧,爲了讓你們對for更加感興趣,咱們先來分析一下for語句的一些注意事項,以後,再讓你們看看更爲強大的for語句實例。
一、for語句的形式變量I,能夠換成26個字母中的任意一個,這些字母會區分大小寫,也就是說,%%I和%%i會被認爲不是同一個變量;形式變量I還能夠換成其餘的字符,可是,爲了避免與批處理中的%0~%9這10個形式變量發生衝突,請不要隨意把%%I替換爲%%0 ~%%9中的任意一個;
二、in和do之間的command1表示的字符串或變量能夠是一個,也能夠是多個,每個字符串或變量,咱們稱之爲一個元素,每一個元素之間,用空格鍵、跳格鍵、逗號、分號或等號分隔;
三、for語句依次提取command1中的每個元素,把它的值賦予形式變量I,帶到do後的command2中參與命令的執行;而且每次只提取一個元素,而後執行一次do後的命令語句,而不管這個元素是否被帶到command2中參與了command2的運行;當執行完一次do後的語句以後,再提取command1中的下一個元素,再執行一次command2,如此循環,直到command1中的全部元素都已經被提取完畢,該for語句才宣告執行結束;
其中,第3點是最爲關鍵的,它描述了for語句的執行過程,是for語句的精髓所在,你們必定要牢記這一條,才能深入理解更爲複雜的for流程。
有了以上的基礎,咱們再來看一個例子,這個例子修改了[code1]的部份內容,結果將大不同:
[code2]
@echo off for %%I in (bbs,bathome,net) do echo %%I pause
和[code1]的執行結果[result1]相比,[result2]發生了以下變化:
一、顯示結果分紅了3行(不算最後一行中文提示);
二、每一行都從逗號處被切分;
若是把 bbs.bathome.net 這個字符串中的點號換爲空格、跳格或等號,執行結果將和example2的執行結果別無二致。
如今,咱們來分析一下[code2]代碼中for語句的執行過程:
首先,for語句以逗號爲分隔符,把 bbs,bathome.net 這個字符串切分紅三個元素:bbs、bathome和cn,由此決定了do後的語句將會被執行3次;
而後,第一次執行過程是這樣的:先把 bbs 這個字符串做爲形式變量I的值,帶入do後的語句中加以執行,也就是執行 echo %%I 語句,此時的I值爲bbs,所以,第一次執行的結果,將會在屏幕上顯示bbs這個字符串;第二次執行和第一次執行的過程是同樣的,只不過此時I的值已經被替換爲command1中的第二個元素了,也就是 bathome 這個字符串;如此循環,當第三次echo執行完畢以後,整條for語句纔算執行完畢,此時,將執行下一條語句,也就是pause命令。
其實,這個例子只比上一個例子多了一點花樣,有趣了那麼一點點:一條for語句的執行結果竟然被分紅了3行!
爲了讓你們見識一下for的真正威力,本人絞盡腦汁,翻帖無數,不得要領,萬般無奈之下,只好亮出了塵封在箱底多年的一段代碼:檢測當前硬盤都有哪些分區。
[code3]
@echo off set str=c d e f g h i j k l m n o p q r s t u v w x y z echo 當前硬盤的分區有: for %%i in (%str%) do if exist %%i: echo %%i: pause
這段代碼能檢測硬盤都有哪些分區,包括U盤和移動硬盤的分區,可是,當光驅中有盤的時候,也會被列出來,這是本代碼的一個缺憾,在之後的講解中,我將向你們講述如何消除這個瑕疵,敬請關注本系列的後續章節。
高級應用:
想知道當前目錄下都有哪些文件嗎?請用下面的代碼:
@echo off for %%i in (*.*) do echo "%%i" pause
想列出當前目錄下全部的文本文件嗎?請用下面的代碼
@echo off for %%i in (*.txt) do echo "%%i" pause
想列出只用兩個字符做爲文件名的文本文件嗎?(注:實際上這個代碼是輸出少於或等於兩個字符做爲文件名的文本文件)請用下面的代碼:
@echo off for %%i in (??.txt) do echo "%%i" pause
題外話:
一、列出當前目錄下各類文件的方法,最簡單的仍是用dir命令,可是,從以上代碼中,各位能夠加深對for語句執行流程的理解(用到了通配符*和?);
二、注意:以上代碼不能列出含有隱藏或系統屬性的文件;(注:這裏其實有一個頗有趣的現象,windows中的系統文件通常具有兩種屬性——隱藏和系統;可是你若是測試的話就會發現,加上+s屬性,可是不加+h的文件是能夠被簡單的for顯示出來的。
例如:
@echo off attrib +s 1.txt For %%i in (*.txt) do Echo %%i pause
這裏的1.txt在結果中顯示出來了。因此「以上代碼不能列出含有隱藏或系統屬性的文件」是不許確的,而因該說成「以上代碼不能列出含有隱藏屬性的文件」)
3、文本解析顯神威:for /f 用法詳解
前言
for /f 是個十分強大的傢伙。
若是說,for語句是批處理中最強大的語句的話,那麼,for /f 就是精華中的精華。
for /f 的強大,和它擁有衆多的開關密切相關。由於開關衆多,因此用法複雜,本章將分紅若干小節,爲你們逐一介紹強大的 for /f 語句。
(一)爲解析文本而生:for /f 的基本用法
全部的對象,不管是文件、窗體、仍是控件,在全部的非機器語言看來,無外乎都是形如"c:\test.txt"、"CWnd"之類的文本信息;而全部的對象,具體的如ini文件中的某條配置信息、註冊表中的某個鍵值、數據庫中的某條記錄……都只有轉化爲具備必定格式的文本信息,方可被代碼識別、操控。能夠說,編程的很大一部分工做,都是在千方百計絞盡腦汁如何提取這些文本信息。
而提取文本信息,則是for /f的拿手好戲:讀取文件內容;提取某幾行字符;截取某個字符片斷;對提取到的內容再切分、打亂、雜糅……只要你所能想到的花樣,for /f 都會千方百計幫你辦到,由於,for /f 就是被設計成專門用於解析文本的。
先來看個例子。
假若有個文本文件test.txt,內容以下:
[txt1]
論壇的目標是:不求最大,但求最好,作最實用的批處理論壇。 論壇地址:bbs.bathome.net。 這裏是:新手晉級的福地,高手論劍的天堂。
那麼,將以下代碼保存爲test.cmd,並放在test.txt同一目錄下運行,將會在屏幕上原樣顯示test.txt的內容:
[code4]
@echo off for /f %%i in (test.txt) do echo %%i pause
這段代碼,主要是讓你樹立這樣一種觀念:讀取文本文件的內容(注:改成「逐行分析文本文件的內容」,由於讀取文本文件內容的方法命令有不少,好比重定向輸入,又好比type/more/find/sort等命令),請使用 for /f 語句!
進階話題:for /f 語句是把整個test.txt一次性顯示出來的?
在這段代碼中,雖然執行結果是把test.txt中的全部內容都顯示出來了,貌似 for /f 語句是把整個test.txt一次性顯示到屏幕上,實際上並不是如此。
不管for語句作何種變化,它的執行過程仍然遵循基本的for流程:依次處理每一個元素,直到全部的元素都被處理爲止。只不過在for /f語句中,這裏的元素是指文件中的每一行,也就是說,for /f 語句是以行爲單位處理文本文件的。這是一條極爲重要的規則,在上一章中也強調過它的重要性,但願在接下來的學習過程當中,你能時刻牢記這一原則,那麼,不少問題將會迎刃而解。如下是驗證這一說法的演示代碼(在[code4]的基礎上添加了&pause語句):
[code5]
@echo off for /f %%i in (test.txt) do echo %%i&pause pause
(二) 切分字符串的利器:delims=
也許你對[code4]這段代碼不屑一顧:不就是把test.txt的內容顯示出來了麼?好像用處不大啊。
好吧,咱們來玩個魔術。
仍是[txt1]這段文本,把[code4]改造一下:
[code6]
@echo off for /f "delims=," %%i in (test.txt) do echo %%i pause
再次運行test.cmd,看到什麼變化了嗎?
[result2]
論壇的目標是:不求最大 論壇地址:bbs.bathome.net。 這裏是:新手晉級的福地 請按任意鍵繼續...
結果,你驚奇地發現,每行第一個逗號以後的全部內容都不見了(若是有不存在逗號的行,則保留原樣),也就說,你成功地提取到了每行第一個逗號以前的全部內容!
試想一下,這段代碼會有什麼用呢?
若是別人給了你一個軟件清單,每行都是"英文軟件名(逗號)中文軟件名"的格式,而你卻只想保留英文名的時候,這段代碼將是多麼有用啊!再假設,有這麼一個IP文件,第一列是數字格式的IP地址,第二列是具體的空間地址,列與列之間用逗號分隔,而你想提取其中數字格式的IP,呵呵,我不說你也知道該怎麼辦了吧?
要是文本內容不是以逗號分隔,而是以其餘符號分隔,那麼,把"delims=,"的逗號換成相應的符號就能夠了。
在這裏,咱們引入了一個新的開關:"delims=,",它的含義是:以逗號做爲被處理的字符串的分隔符號。
在批處理中,指定分隔符號的方法是:添加一個形如 "delims=符號列表" 的開關,這樣,被處理的每行字符串都會被符號列表中羅列出來的符號切分開來。
須要注意的是:若是沒有指定"delims=符號列表"這個開關,那麼,for /f 語句默認以空格鍵或跳格鍵做爲分隔符號。請把[txt1]中不一樣位置上的標點符號改成空格或跳格,再運行[code4]試試。
進階話題:若是我要指定的符號不止一個,該怎麼辦?
在上面的講解中,我提到了指定分隔符號的方法:添加一個形如"delims=符號列表"的開關。不知道你注意到沒有,個人說法是"符號列表"而非"符號",這是大有講究的,由於,你能夠一次性指定多個分隔符號!
仍是以[txt1]爲例,把[code6]再改造一下
[code7]
@echo off for /f "delims=.," %%i in (test.txt) do echo %%i pause
結果顯示:
[result3]
論壇的目標是:不求最大
論壇地址:bbs
這裏是:新手晉級的福地
請按任意鍵繼續...
這樣,第一個點號或第一個逗號以前的內容都被提取出來了。
[code7]的執行過程是:逐行讀取test.txt中的內容,以點號和逗號切分每一行的內容(不存在點號和逗號的行,則再也不切分,爲了描述的方便,咱們把被點號或逗號切分的一個一個的字符串片斷,稱之爲節),而後,for /f 會提取第一節的內容做爲最終結果,顯示在屏幕上。須要注意的是,在這裏,全部行的字符串被切分紅了兩個以上的節,可是,[code7]的代碼只會提取第一節字符串的內容,由於 for /f 語句默認只提取第一節的符串。
(三) 定點提取:tokens=
上一節在講解 delims= 的時候,我一再強調 for /f 默認只能提取到第一節的內容,如今咱們來思考一個問題:若是我要提取的內容不在第一節上,那怎麼辦?
這回,就該輪到 tokens= 出馬了。
tokens= 後面通常跟的是數字,如 tokens=2,也能夠跟多個,可是每一個數字之間用逗號分隔,如 tokens=3,5,8,它們的含義分別是:提取第2節字符串、提取第三、第5和第8節字符串。注意,這裏所說的「節」,是由 delims= 這一開關劃分的,它的內容並非一成不變的。
下面來看一個例子:
[txt2]
尺有所短,寸有所長,學好批處理沒商量,考慮問題複雜化,解決問題簡潔化。
對[txt2]這段文本,假設它們保存在文件test.txt中,若是我想提取「學好批處理沒商量」這句話,該如何寫代碼呢?
咱們稍微觀察一下[txt2]就會發現,若是以逗號做爲切分符號,就正好能夠把「學好批處理沒商量」化爲單獨的一「節」,結合上一節的講解,咱們知道,"delims=," 這個開關是不可缺乏的,而要提取的內容在以逗號切分的第3節上,那麼,tokens= 後面的數字就應該是3了,最終的代碼以下:
[code8]
@echo off for /f "delims=, tokens=3" %%i in (test.txt) do echo %%i pause
若是咱們如今要提取的不僅一個「節」,而是多個,那又怎麼辦呢?好比,要提取以逗號切分的第2節和第5節字符串,是寫成這樣嗎?
[code9]
@echo off for /f "delims=, tokens=2,5" %%i in (test.txt) do echo %%i pause
運行批處理後發現,執行結果只顯示了第2節的內容。
原來,echo 後面的 %%i 只接收到了 tokens=2,5 中第一個數值2所表明的那個字符串,而第二個數值5所表明的字符串由於沒有變量來接收,因此就沒法在執行結果中顯示出來了。
那麼,要如何接收 tokens= 後面多個數值所指代的內容呢?
for /f 語句對這種狀況作以下規定:
若是 tokens= 後面指定了多個數字,若是形式變量爲%%i,那麼,第一個數字指代的內容用第一個形式變量%%i來接收,第二個數字指代的內容用第二個形式變量%%j來接收,第三個數字指代的內容用第三個形式變量%%k來接收……第N個數字指代的內容用第N個形式變量來接收,其中,形式變量遵循字母的排序,第N個形式變量具體是什麼符號,由第一個形式變量來決定:若是第一個形式變量是%%i,那麼,第二個形式變量就是%%j;若是第一個形式變量用的是%%x,那麼,第二個 形式變量就是%%y。
如今回頭去看[code9],你應該知道如何修改才能知足題目的要求了吧?修改結果以下:
[code10]
@echo off for /f "delims=, tokens=2,5" %%i in (test.txt) do echo %%i %%j pause
若是有這樣一個要求:顯示[txt2]中的內容,可是逗號要替換成空格,如何編寫代碼?
結合上面所學的內容,稍加思索,你可能很快就得出了答案:
[code11]
@echo off for /f "delims=, tokens=1,2,3,4,5" %%i in (test.txt) do echo %%i %%j %%k %%l %%m pause
寫完以後,你可能意識到這樣一個問題:假如要提取的「節」數不是5,而是10,或者20,或者更多,難道我也得從1寫到十、20或者更多嗎?有沒有更簡潔的寫法呢?
答案是有的,那就是:若是要提取的內容是連續的多「節」的話,那麼,連續的數字能夠只寫最小值和最大值,中間用短橫鏈接起來便可,好比 tokens=1,2,3,4,5 能夠簡寫爲 tokens=1-5 。
還能夠把這個表達式寫得更復雜一點:tokens=1,2-5,tokens=1-3,4,5,tokens=1-4,5……怎麼方便就怎麼寫吧。
你們可能還看到一種比較怪異的寫法:
[code12]
@echo off for /f "delims=, tokens=1,*" %%i in (test.txt) do echo %%i %%j pause
結果,第一個逗號不見了,取代它的是一個空格符號,其他部分保持不變。
其中奧妙就在這個星號上面。
tokens=後面所接的星號具有這樣的功能:字符串從左往右被切分紅緊跟在*以前的數值所表示的節數以後,字符串的其他部分保持不變,總體被*所表示的一個變量接收。
理論講解是比較枯燥的,特別是爲了嚴密起見,還使用了不少限定性的修飾詞,致使句子很長,增長了理解的難度,咱們仍是結合[code12]來說解一下吧。
[txt2] 的內容被切分,切分符號爲逗號,當切分完第一節以後,切分動做再也不繼續下去,由於 tokens=1,* 中,星號前面緊跟的是數字1;第一節字符串被切分完以後,其他部分字符串不作任何切分,總體做爲第二節字符串,這樣,[txt2]就被切分紅了兩節,分別 被變量%%i和變量%%j接收。
以上幾種切分方式能夠結合在一塊兒使用。不知道下面這段代碼的含義你是否看得懂,若是看不懂的話,那就運行一下代碼,而後反覆揣摩,你必定會更加深入地理解本節所講解的內容的:
[code13]
@echo off for /f "delims=, tokens=1,3-4,*" %%i in (test.txt) do echo %%i %%j %%k %%l pause
(四) 跳過無關內容,直奔主題:skip=n
不少時候,有用的信息並非貫穿文本內容的始終,而是位於第N行以後的行內,爲了提升文本處理的效率,或者不受多餘信息的干擾,for /f 容許你跳過這些無用的行,直接從第N+1行開始處理,這個時候,就須要使用參數 skip=n,其中,n是一個正整數,表示要跳過的行數。例如:
[code14]
@echo off for /f "skip=2" %%i in (test.txt) do echo %%i pause
這段代碼將跳過頭兩行內容,從第3行起顯示test.txt中的信息。
(五) 忽略以指定字符打頭的行:eol=
在cmd窗口中敲入:for /?,相關的解釋爲:
eol=c -指一個行註釋字符的結尾(就一個)
FOR /F "eol=; tokens=2,3* delims=, " %i in (myfile.txt) do @echo %i %j %k 會分析 myfile.txt 中的每一行,忽略以分號打頭的那些行……
第一條解釋狗屁不通,頗爲費解:行註釋字符的結尾是什麼意思?「(就一個)」怎麼回事?結合第二條解釋,才知道eol有忽略指定行的功能。可是,這兩條解釋是互相矛盾的:究竟是忽略以指定字符打頭的行,仍是忽略以指定字符結尾的行?
實踐是檢驗真理的惟一標準,仍是用代碼來檢驗一下eol的做用吧:
[code15]
@echo off for /f "eol=;" %%i in (test.txt) do echo %%i pause
結果,那些以分號打頭的行沒有顯示出來。
因而可知,第二條解釋是正確的,eol= 的準確含義是:忽略以指定字符打頭的行。而第一條的「結尾」純屬微軟在信口開河。
那麼,「(就一個)」又做何解釋呢?
試試這個代碼:
[code16]
@echo off for /f "eol=,;" %%i in (test.txt) do echo %%i pause
此時,屏幕上出現「此時不該有" ;"。」的報錯信息。可見,在指定字符的時候,只能指定1個——在不少時候,我對這樣的設計很有微詞而又迫不得已:爲何只能指定1個而不是多個?要忽略多個還得又是if又是findstr加管道來屢次過濾,那效率實在過低下了——能用到的功能基本上都提供,可是卻又作不到更好,批處理,你的功能爲何那麼弱?
不知道你們注意到沒有,若是test.txt中有以分號打頭的行,那麼,這些行在代碼[code14]的執行結果中將憑空消失。
原來,for /f 語句是默認忽略以分號打頭的行內容的,正如它默認以空格鍵或跳格鍵做爲字符串的切分字符同樣。(注:eol=;這種默認設置,在delims=;時變得無效。)
不少時候,咱們能夠充分利用這個特色,好比,在設計即將用for讀取的配置文件的時候,能夠在註釋文字的行首加上分號,例如在編寫病毒文件查殺代碼的時候,能夠經過for語句來讀取病毒文件列表,那麼,病毒文件列表.ini這個配置文件能夠這樣寫:
;如下是常見的病毒文件,請見一個殺一個 ;copyleft:沒有 qq.exe msn.exe iexplore.exe
若是要取消這個默認設置,可選擇的辦法是:
一、爲eol=指定另一個字符;
二、使用 for /f "eol=" 語句,也就是說,強制指定字符爲空,就像對付delims=同樣。
(六)如何決定該使用 for /f 的哪一種句式?(兼談usebackq的使用)
for /f %%i in (……) do (……) 語句有好幾種變形語句,不一樣之處在於第一個括號裏的內容:有的是用單引號括起來,有的是用雙引號包住,有的不用任何符號包裹,具體格式爲:
一、for /f %%i in (文件名) do (……) 二、for /f %%i in ('命令語句') do (……) 三、for /f %%i in ("字符串") do (……)
看到這裏,我想不少人可能已經開始犯了迷糊了:若是要解決一個具體問題,面對這麼多的選擇,如何決定該使用哪一條呢?
實際上,當我在上面羅列這些語句的時候,已經有所提示了,不知道你是否注意到了。
若是你一時沒法參透其中奧妙,那也無妨,請聽我一一道來即是。
一、當你但願讀取文本文件中的內容的話,第一個括號中不用任何符號包裹,應該使用的是第1條語句;例如:你想顯示test.txt中的內容,那麼,就使用 for /f %%i in (test.txt) do echo %%i;
二、當你讀取的是命令語句執行結果中的內容的話,第一個括號中的命令語句必須使用單引號包裹,應該使用的是第2條語句;例如:你想顯示當前目錄下文件名中含有test字符串的文本文件的時候,應該使用 for /f %%i in ('dir /a-d /b *test*.txt') do echo %%i 這樣的語句;
三、當你要處理的是一個字符串的時候,第一個括號中的內容必須用雙引號括起來,應該是用的是第3條語句;例如:當你想把bbs.bathome.net這串字符中的點號換爲短橫線並顯示出來的話,能夠使用 for /f "delims=. tokens=1-3" %%i in ("bbs.bathome.net") do echo %%i-%%j-%%k 這樣的語句。
很顯然,第一個括號裏是否須要用符號包裹起來,以及使用什麼樣的符號包裹,取決於要處理的對象屬於什麼類型:若是是文件,則無需包裹;若是是命令語句,則用單引號包裹;若是是字符串,則使用雙引號括起來。
固然,事情並非絕對如此,若是細心的你想到了批處理中難纏的特殊字符,你確定會頭大如鬥。
或許你頭腦中靈光一閃,已經想到了一個十分頭痛的問題:在第1條語句中,若是文件名中含有空格或&,該怎麼辦?
照舊嗎?
拿個叫 test 1.txt 的文件來試試。
你很快寫好了代碼,新建文件-->碼字-->保存爲批處理,先後費時不到1分鐘:
[code17]
@echo off for /f %%i in (test 1.txt) do echo %%i pause
你興沖沖地雙擊批處理,運行後,屏幕上出現了可恥的報錯信息:系統找不到文件 test 。
當你把 test 1.txt 換成 test&1.txt 後,更怪異的事情發生了:CMD窗口在你眼前一閃而過,而後,優雅地消失了。
你可能以爲本身的代碼寫錯了某些符號,你再仔細的檢查了一次,確認沒有筆誤,而後,你再次雙擊批處理,結果問題照舊;你開始懷疑其餘程序對它可能有影響,因而關掉其餘窗口,再運行了一次,問題依舊;你不服氣地連續運行了好幾回,仍是一樣的結果。
怪哉!
你一拍大腿,猛然想起了一件事:當路徑中含有特殊字符的時候,應該使用引號把路徑括起來。對,就是它了!
可是,當你把代碼寫出來以後,你很快就焉了:for /f %%i in ("test 1.txt") do echo %%i,這不就是上面提到的第3條 for /f 命令的格式嗎?批處理會把 test 1.txt 這個文件名識別爲字符串啊!
你百無聊賴地在CMD窗口中輸入 for /? ,並重重地敲下了回車,漫無目的地在幫助信息中尋找,但願能找到點什麼。
結果還真讓你到了點什麼。
你看到了這樣的描述:
usebackq - 指定新語法已在下類狀況中使用:
在做爲命令執行一個後引號的字符串而且一個單引號字符爲文字字符串命令並容許在 filenameset 中使用雙引號擴起文件名稱。
可是,通讀一遍以後,你卻如墜五里霧中,不知所云。
還好,下面有個例子,並配有簡單的說明:
FOR /F "usebackq delims==" %i IN (`set`) DO @echo %i 會枚舉當前環境中的環境變量名稱。
你仔細對比了for /f語句使用usebackq和不使用usebackq時在寫法上的差異,很快就找到了答案:當使用了usebackq以後,若是第一個括號中是一條命令語句,那麼,就要把單引號'改爲後引號`(鍵盤左上角esc鍵下面的那個按鍵,與~在同一鍵位上)。
回過頭去再看那段關於usebackq的描述,字斟句酌,反覆揣摩,終於被你破譯了天機:usebackq 是一個加強型參數,當使用了這個參數以後,原來的for語句中第一個括號內的寫法要作以下變更:若是第一個括號裏的對象是一條命令語句的話,原來的單引號'要改成後引號`;若是第一個括號裏的對象是字符串的話,原來的雙引號"要改成單引號';若是第一個括號裏的對象是文件名的話,要用雙引號"括起來。
驗證一下,把[code17]改寫成以下代碼:
[code18]
@echo off for /f "usebackq" %%i in ("test 1.txt") do echo %%i pause
測試經過!
此時,你極可能會仰天長嘆:Shit,微軟這該死的機器翻譯!
至於把[code17]代碼中的空格換成&後,CMD窗口會直接退出,那是由於&是複合語句的鏈接符,CMD在預處理的時候,會優先把&先後兩部分做爲兩條語句來解析,而不是你們想象中的一條完整的for語句,從而產生了嚴重的語法錯誤。由於牽涉到預處理機制問題,不屬於本節要討論的內容,在此不作詳細講解。
這個時候,咱們會吃驚地發現,區區一條for語句,居然有多達6種句型:
一、for /f %%i in (文件名) do (……) 二、for /f %%i in ('命令語句') do (……) 三、for /f %%i in ("字符串") do (……) 四、for /f "usebackq" %%i in ("文件名") do (……) 五、for /f "usebackq" %%i in (`命令語句`) do (……) 六、for /f "usebackq" %%i in ('字符串') do (……)
其中,四、五、6由一、二、3發展而來,他們有這樣的對應關係:1-->四、2-->五、3-->6。
好在後3種情形並不經常使用,因此,緊緊掌握好前三種句型的適用情形就能夠了,不然,要在這麼多句型中肯定選擇哪一條語句來使用,還真有點讓人頭腦發懵。
至於 for /f 爲何要增長usebacq參數,我只爲第4條語句找到了合理的解釋:爲了兼容文件名中所帶的空格或&。它在第五、6條語句中爲何還有存在的必要,我也不是很明白,這有待於各位去慢慢發現。(注:這種解釋雖然有點不靠譜,但也算一種解釋,你們將就看看吧。啓用usebackq選項的時候,「文件名」取代了「字符串」,那麼「字符串」只好改變爲「命令語句」,「命令語句」只好用後引號從新表示——簡而言之,是「文件名」符號改變引發的蝴蝶效應。言外之意:usebackq除了在處理帶空格的文件名時會用到外,根本就沒有其它的出場機會和存在價值。)
(七)變量延遲詳解
變量延遲在for語句中起着相當重要的做用,不僅是在for語句中,在其餘的複合語句中,它也在幕後默默地工做着,爲了突出它的重要性,本節內容在單獨的樓層中發出來,但願引發你們的重視。
對於批處理新手而言,「變量延遲」這個概念極可能聞所未聞,可是,它卻像一堵橫亙在你前進道路上的無形高牆,你感覺不到它的存在,但當你試圖往前衝時,它會把你狠狠地彈回來,讓你沒法逾越、無功而返;而一旦找到了越過它的方法,你就會發現,在for的世界裏,前面已是一片坦途,而你對批處理的理解,又上升到了一個新的境界。
例如,你編寫了這樣一個代碼:
[code19]
@echo off set num=0&&echo %num% pause
你的本意是想對變量num賦值以後,再把這個值顯示出來,結果,顯示出來的並非0,而是顯示:ECHO 處於關閉狀態。
之因此會出錯,是由於「變量延遲」這個傢伙在做怪。
在講解變量延遲以前,咱們須要瞭解一下批處理的執行過程,它將有助於咱們深刻理解變量延遲。
批處理的執行過程是怎樣的呢?
「自上而下,逐條執行」,我想,這個經典的說法你們都已經耳熟能詳了,沒事的時候倒着念,也還別有一番古韻呢,可是,我想問你們的是,你們真的深入地理解了這句話的含義了嗎?
「自上而下」,這一條和咱們本節的講解關係不大,暫時略過不說,後一條,「逐條執行」和變量延遲有着莫大的干係,它是咱們本節要關注的重點。
不少人每每認爲一行代碼就是一條語句,從而把「逐條執行」與「逐行執行」等同起來,這就大錯特錯了。
莫非「逐條執行」裏暗藏着玄機?
正是如此。
「逐條」並不等同於「逐行」。這個「條」,是「一條完整的語句」的意思,並非指「一行代碼」。在批處理中,是否是一條完整的語句,並非以行來論的,而是要看它的做用範圍。
什麼樣的語句纔算「一條完整的語句」呢?
一、在複合語句中,整個複合語句是一條完整的語句,而不管這個複合語句佔用了多少行的位置。常見的複合語句有:for語句、if……else語句、用 鏈接符&、||和&&鏈接的語句,用管道符號|鏈接的語句,以及用括號括起來的、由多條語句組合而成的語句塊;
二、在非複合語句中,若是該語句佔據了一行的位置,則該行代碼爲一條完整的語句。
例如:
[code20]
1 @echo off 2 set num=0 3 for /f %%i in ('dir /a-d /b *.exe') do ( 4 set /a num+=1 5 echo num 當前的值是 %num% 6 ) 7 echo 當前目錄下共有 %num% 個exe文件 8 dir /a-d /b *.txt|findstr "test">nul&&( 9 echo 存在含有 test 字符串的文本本件 10 ) || echo 不存在含有 test 字符串的文本文件 11 if exist test.ini ( 12 echo 存在 test.ini 文件 13 ) else echo 不存在 test.ini 文件 14 pause
上面的代碼共有14行,可是隻有完整的語句只有7條,它們分別是:
第1條:第1行的echo語句;
第2條:第2行的set語句;
第3條:第三、四、五、6行上的for複合語句;
第4條:第7行的echo語句;
第5條:第八、九、10行上用&&和||鏈接的複合語句;
第6條:第十一、十二、13行上的if……else複合語句;
第7條:第14行上的pause語句。
在這裏,我之因此要花這麼長的篇幅來講明一行代碼並不見得就是一條語句,是由於批處理的執行特色是「逐條」執行而不是「逐行」執行,澄清了這個誤解,將會更加理解批處理的預處理機制。
在代碼「逐條」執行的過程當中,cmd.exe這個批處理解釋器會對每條語句作一些預處理工做,這就是批處理中大名鼎鼎的「預處理機制」。
預處理的大體情形是這樣的:首先,把一條完整的語句讀入內存中(無論這條語句有多少行,它們都會被一塊兒讀入),而後,識別出哪些部分是命令關鍵字,哪些是開關、哪些是參數,哪些是變量引用……若是代碼語法有誤,則給出錯誤提示或退出批處理環境;若是順利經過,接下來,就把該條語句中全部被引用的變量及變量兩邊的百分號對,用這條語句被讀入內存之就已經賦予該變量的具體值來替換……當全部的預處理工做完成以後,批處理纔會執行每條完整語句內部每一個命令的原有功能。也就是說,若是命令語句中含有變量引用(變量及緊鄰它左右的百分號對),而且某個變量的值在命令的執行過程當中被改變了,即便該條語句內部的其餘地方也用到了這個變量,也不會用最新的值去替換它們,由於某條語句在被預處理的時候,全部的變量引用都已經被替換成字符串常量了,變量值在複合語句內部被改變,不會影響到語句內部的其餘任何地方。
順便說一下,運行代碼[code20]以後,將在屏幕上顯示當前目錄下有多少個exe文件,是否存在含有 test 字符串的文本文件,以及是否存在 test.ini 這個文件等信息。讓不少人百思不得其解的是:若是當前目錄下存在exe文件,那麼,有多少個exe文件,屏幕上就會提示多少次 "num 當前的值是 0" ,而不是顯示1到N(N是exe文件的個數)。
結合上面兩個例子,咱們再來分析一下,爲何這兩段代碼的執行結果和咱們的指望有一些差距。
在[code19]中,set num=0&&echo %num%是一條複合語句,它的含義是:把0賦予變量num,成功後,顯示變量num的值。
雖然是在變量num被賦值成功後才顯示變量num的值,可是,由於這是一條複合語句,在預處理的時候,&&後的%num%只能被set語句以前的語句賦予變量num的具體值來替換,而不能被複合語句內部、&&以前的set語句對num所賦予的值來替換,可見,此num非彼num。但是,在這條複合語句以前,咱們並無對變量num賦值,因此,&&以後的%num%是空值,至關於在&&以後只執行了 echo 這一命令,因此,會顯示 echo 命令的當前狀態,而不是顯示變量num的值(雖然該變量的值被set語句改變了)。
在[code20]中,for語句的含義是:列舉當前目錄下的exe文件,每發現一個exe文件,變量num的值就累加1,並顯示變量num的值。
看了對[code19]的分析以後,再來分析[code20]就再也不那麼困難了:第三、四、5行上的代碼共同構成了一條完整的for語句,而語句"echo num 當前的值是 %num%"與"set /a num+=1"同處複合語句for的內部,那麼,第4行上set改變了num的值以後,並不能對第5行上的變量num有任何影響,由於在預處理階段,第5行上的變量引用%num%已經被在for以前就賦予變量num的具體值替換掉了,它被替換成了0(是被第2行上的set語句賦予的)。
若是想讓代碼[code19]的執行結果中顯示&&以前賦予num的值,讓代碼[code20]在列舉exe文件的時候,從1到N地顯示exe文件的數量,那又該怎麼辦呢?
對代碼[code19],能夠把用&&鏈接複合語句拆分爲兩條單獨的語句,寫成:
@echo off set num=0 echo %num% pause
可是,這不是咱們此次想要的結果。
對這兩段代碼都適用的辦法是:使用變量延遲擴展語句,讓變量的擴展行爲延遲一下,從而獲取咱們想要的值。
在這裏,咱們先來充下電,看看「變量擴展」有是怎麼一回事。
用CN-DOS裏批處理達人willsort的原話,那就是:「在許多可見的官方文檔中,均將使用一對百分號閉合環境變量以完成對其值的替換行爲稱之爲「擴展(expansion)」,這實際上是一個第一方的概念,是從命令解釋器的角度進行稱謂的,而從咱們使用者的角度來看,則能夠將它看做是引用(Reference)、調用(Call)或者獲取(Get)。」(見:什麼狀況下該使用變量延遲?http://www.cn-dos.net/forum/viewthread.php?tid=20733)說得直白一點,所謂的「變量擴展」,實際上就是很簡單的這麼一件事情:用具體的值去替換被引用的變量及緊貼在它左右的那對百分號。
既然只要延遲變量的擴展行爲,就能夠得到咱們想要的結果,那麼,具體的作法又是怎樣的呢?
通常說來,延遲變量的擴展行爲,能夠有以下選擇:
一、在適當位置使用 setlocal enabledelayedexpansion 語句;
二、在適當的位置使用 call 語句。
使用 setlocal enabledelayedexpansion 語句,那麼,[code19]和[code20]能夠分別修改成:
@echo off setlocal enabledelayedexpansion set num=0&&echo !num! pause
@echo off set num=0 setlocal enabledelayedexpansion 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 echo 不存在 test.ini 文件 pause
使用第call語句,那麼,[code19]和[code20]能夠分別修改成:
@echo off set num=0&&call echo %%num%% pause
@echo off set num=0 for /f %%i in ('dir /a-d /b *.exe') do ( set /a num+=1 call 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
因而可知,若是使用 setlocal enabledelayedexpansion 語句來延遲變量,就要把本來使用百分號對閉合的變量引用改成使用感嘆號對來閉合;若是使用call語句,就要在原來命令的前部加上 call 命令,並把變量引用的單層百分號對改成雙層。 其中,由於call語句使用的是雙層百分號對,容易令人犯迷糊,因此用得較少,經常使用的是使用 setlocal enabledelayedexpansion 語句(set是設置的意思,local是本地的意思,enable是可以的意思,delayed是延遲的意思,expansion是擴展的意思,合起來, 就是:讓變量成爲局部變量,並延遲它的擴展行爲)。
經過上面的分析,咱們能夠知道:
一、爲何要使用變量延遲?由於要讓複合語句內部的變量實時感知到變量值的變化。
二、在哪些場合須要使用變量延遲語句?在複合語句內部,若是某個變量的值發生了改變,而且改變後的值須要在複合語句內部的其餘地方被用到,那麼,就須要使用變量延遲語句。而複合語句有:for語句、if……else語句、用鏈接符&、||和&&鏈接的語句、用管道符號|鏈接的語句,以及用括號括起來的、由多條語句組合而成的語句塊。最多見的場合,則是for語句和if……else語句。
三、怎樣使用變量延遲?
方法有兩種:
① 使用 setlocal enabledelayedexpansion 語句:在獲取變化的變量值語句以前使用setlocal enabledelayedexpansion,並把本來使用百分號對閉合的變量引用改成使用感嘆號對來閉合;
② 使用 call 語句:在原來命令的前部加上 call 命令,並把變量引用的單層百分號對改成雙層。
「變量延遲」是批處理中一個十分重要的機制,它因預處理機制而生,用於複合語句,特別是大量使用於強大的for語句中。只有熟練地使用這一機制,才能在for的世界中如魚得水,讓本身的批處理水平更上一層樓。不少時候,對for的處理機制,咱們一直是霧裏看花,即便偶有所得,也只是只可意會難以言傳。但願你們反覆揣摩,多加練習,不少細節上的經驗,是隻有經過大量的摸索才能獲得的。
本節內容在原理上參考了這篇文章:什麼狀況下該使用變量延遲?http://www.cn-dos.net/forum/viewthread.php?tid=20733,在本論壇中的地址是:http://bbs.bathome.net/viewthread.php?tid=2899
4、翻箱倒櫃遍歷文件夾:for /r
(一)for /r 的做用及用法
按照幫助信息裏文縐縐的說法,for /r 的做用是「遞歸」,咱們換一個通俗一點的,叫「遍歷文件夾」。
更詳細的解釋就是:在下面的語句中,若是「元素集合」中只是一個點號,那麼,這條語句的做用就是:列舉「目錄」及其之下的全部子目錄,對這些文件夾都 執行「命令語句集合」中的命令語句。其做用與嵌套進 for /f 複合語句的 "dir /ad /b /s 路徑" 功能相似。若是省略了「目錄」,將在當前目錄下執行前面描述的操做。
for /r 目錄 %%i in (元素集合) do 命令語句集合
先來個代碼加強一下印象:
[code21]
@echo off for /r d:\test %%i in (.) do echo %%i pause
執行的結果以下所示:
d:\test\. d:\test\1\. d:\test\2\. d:\test\3\.
效果就是顯示 d:\test 目錄及其之下是全部子目錄的路徑,其效果與 dir /ad /b /s d:\test 相似。若要說到二者的區別,能夠概括出3點:
一、for /r 列舉出來的路徑最後都帶有斜槓和點號,而 dir 語句則沒有,會對獲取到的路徑進行進一步加工產生影響;
二、for /r 不能列舉帶隱藏屬性的目錄,而 dir 語句則能夠經過指定 /a 後面緊跟的參數來獲取帶指定屬性的目錄,更加靈活;
三、若要對獲取到的路徑進行進一步處理,則須要把 dir 語句放入 for /f 語句中進行分析,寫成 for /f %%i in ('dir /ad /b /s') do …… 的形式;因爲 for /r 語句是邊列舉路徑邊進行處理,因此,在處理大量路徑的時候,前期不會感到有停頓,而 for /f 語句則須要等到 dir /ad /b /s 語句把全部路徑都列舉完以後,再讀入內存進行處理,因此,在處理大量路徑的時候,前期會感到有明顯的停頓。
第2點差異很容易被你們忽視,致使用 for /r 列舉路徑的時候會形成遺漏;而第3點則會讓你們有更直觀的感覺,很容易感受到二者之間的差異。
要是「元素集合」不是點號呢?那又如何?
來看看這個代碼:
[code22]
@echo off for /r d:\test %%i in (a b c) do echo %%i pause
運行的結果是:
D:\test\1\a D:\test\1\b D:\test\1\c D:\test\2\a D:\test\2\b D:\test\2\c D:\test\3\a D:\test\3\b D:\test\3\c
原來,它的含義是:列舉 d:\test 及其全部的子目錄,對全部的目錄路徑都分別添加a、b、c以後再顯示出來。
再來看一個代碼:
[code23]
@echo off for /r d:\test %%i in (*.txt) do echo %%i pause
運行結果是:
D:\test\test.txt D:\test\1\1.txt D:\test\1\2.txt D:\test\2\a.txt D:\test\2\b.txt D:\test\3\1.txt
這段代碼的含義是:列舉 d:\test 及其全部子目錄下的txt文本文件(以.txt結尾的文件夾不會被列出來)。
咱們再回過頭來概括一下這個語句的做用:
for /r 目錄 %%i in (元素集合) do 命令語句集合
上面語句的做用是:
一、列舉「目錄」及該目錄路徑下全部子目錄,並把列舉出來的目錄路徑和元素集合中的每個元素拼接成形如「目錄路徑\元素」格式的新字符串,而後,對每一條這樣的新字符串執行「命令語句集合」中的每一條命令;
特別的是:當「元素集合」帶以點號分隔的通配符?或*的時候,把「元素集合」視爲文件(不視爲文件夾),整條語句的做用是匹配「目錄」所指文件夾及其全部子文件夾下匹配的文件;若不以點號分隔,則把「元素集合」視爲文件夾(不視爲文件);
二、當省略掉「目錄」時,則針對當前目錄;
三、當元素集合中僅僅是一個點號的時候,將只列舉目錄路徑;
(二)for /r 仍是 dir /ad /b /s?列舉目錄時該如何選擇
前面已經說過,當列舉目錄時,for /r 和 dir /ad /b /s 的效果是很是相似的,這就產生了一個問題:當我要獲取目錄路徑並進行進一步處理的時候,二者之間,我該如何選擇?
這個問題,前面其實已經有過一些討論,如今咱們再來做詳細的分析。
咱們來看一下二者各自的優缺點:
一、for /r:
1)優勢:
① 只經過1條語句就能夠同時實現獲取目錄路徑和處理目錄路徑的操做;
② 遍歷文件夾的時候,是邊列舉邊處理的,獲取到一條路徑就處理一條路徑,內存佔用小,處理大量路徑的時候不會產生停頓感;
2)缺點:
① 不能獲取到帶隱藏屬性的目錄,會產生遺漏;
② 不能獲取帶指定屬性的目錄
二、dir /ad /s:
1)優勢:
① 能一次性獲取帶任意屬性的目錄,不會產生遺漏;
② 能經過指定不一樣的參數獲取帶任意屬性的目錄,更具靈活性。
2)缺點:
① dir /ad /s 語句僅能獲取到目錄路徑,若要實現進一步的處理,還須要嵌入 for /f 語句中才能實現,寫法不夠簡潔;
② 嵌入 for /f 語句以後,須要寫成 for /f "delims=" %%i in ('dir /ad /b /s') do …… 的格式,受 for /f 語句運行機制的制約,須要先列舉完全部的路徑放入內存以後,才能對每一條路徑進行進一步的處理,處理大量路徑時,內存佔用量偏大,而且在前期會產生明顯的 停頓感,用戶體驗度不夠好;
綜合上述分析,能夠作出以下選擇:
一、若僅僅是爲了獲取某文件夾及其全部子文件夾的路徑的話,請選擇 dir /ad /b /s 語句;
二、若須要過濾帶隱藏屬性的文件夾的話,for /r 和 dir 語句均可以實現,但 for /r 內存佔用小,處理速度快,是上上之選;
三、若須要獲取全部文件夾,則除了 dir /ad /b /s 外,別無選擇,由於 for /r 語句會遺漏帶隱藏屬性的文件夾;
在實際的使用中,我更喜歡使用 for /f 和 dir 的組合,由於它不會產生遺漏,並能給我帶來更靈活的處理方式,惟一須要忍受的,就是它在處理大量路徑時前期的停頓感,以及在這背後稍微有點偏高的內存佔 用;在我追求速度且能夠忽略帶隱藏屬性的目錄的時候,我會換用 for /r 的方案,不過這樣的情形很少——有誰會願意爲了追求速度而容忍遺漏呢?
5、僅僅爲了匹配第一層目錄而存在:for /d
for /d 中 /d ,完整的含義是 /directory,本意是爲了處理文件夾,它的完整語句應該是這樣的:
for /d %%i in (元素集合) do 命令語句集合
當「元素集合」中包含有通配符?或*時,它會匹配文件夾,可是,相比 for /r 而言,這個時候的for /d,其做用就小得可憐了:它僅能匹配當前目錄下的第一級文件夾,或是指定位置上的文件夾,而不能匹配更深層次的子文件夾。
例如:for /d %%i in (d:\test*) do echo %%i 這樣的語句 ,會匹配到形如:d:\test、d:\test一、d:\test2之類的文件夾,若不存在這樣的路徑,將不會有任何回顯。
當「元素集合」中不包含任何的通配符時,它的做用和 "for %%i in (元素集合) do 命令語句集合" 這樣的語句別無二致。
所以,for /d 的角色就變得很微妙了:當「元素集合」中包含通配符?或*時,它的做用就是匹配文件夾,此時,它僅能匹配當前目錄下的第一級文件夾,或是指定位置上的文件夾,在層次深度上不及 for /r,但和 for /r 同樣的壞脾氣:不能匹配帶隱藏屬性的文件夾;在靈活性上不及for /f和dir的組合;當「元素集合」中不包含任何統配符的時候,它徹底是 "for %%i in (元素集合) do ……" 語句的翻版,可是又稍顯複雜。
for /d 的做用是如此有限,我使用的次數是如此之少,以致於我一度找不到它的用武之地,認爲它食之無味,棄之惋惜,徹底是雞肋一塊。
某年某月,我在cmd窗口裏寫下了這樣的代碼:
[code24]
for /d %i in (test*) do @echo %i
個人本意是想查看在個人臨時目錄下,終年累月的測試工做到底創建了多少測試文件夾,以便我隨後把echo換成rd刪除之。這個時候,我發現這條代碼是如此 的簡潔,是 for /r 或 for和 dir /ad /b 的組合所沒法替代的(echo換成rd就能夠直接刪除掉這些測試目錄)。
簡潔的代碼給我帶來的喜悅僅僅持續了短短10幾秒的時間,我便開始了迷惘——能用到for /d的相似情形,貌似少之又少且乏善可陳啊。
(注:正如qzwqzw所言,for /r /d是能夠一塊兒使用的;【在for有限的4個參數中,據我所知只有/r /d能夠一塊兒使用】。
例如:
@echo off For /r /d %%i in (*) do echo %%i pause>nul
效果:
顯示當前目錄下全部的文件夾【包括子文件夾】;等價於 "dir /ad /s /b"。
for /r /d 實際上是對 /d 參數的擴展,/d參數自己只能處理第一層文件夾,可是加上/r參數後就能夠處理全部的子文件夾;
for /r /d依然不能處理隱藏文件夾。
這裏給出使用for /r /d的通常條件: 1.要對文件夾進行操做(dir /ad /s /b能夠顯示,但不能對文件夾進行操做); 2.不處理隱藏文件夾(說到底,仍是for /f 和dir結合的命令更強大些)。
6、計數循環:for /l
/l 者,/loop的縮寫是也,從鳥語翻譯過來,loop就是循環的意思。實際上,全部的for語句,均可以當作是一種「循環」,只是在/l中,特指按照指定次數進行循環罷了。
for /l 語句的完整格式是這樣的:
for /l %%i in (x,y,z) do (……)
在這個語句中,x、y和z都只能取整數,正負皆可,x指代起始值,y指代步長,z爲終止值,具體含義爲:從x開始計數,以y爲步長,直至最接近 z的那個整數值爲止,這之間有多少個數,do後的語句就執行多少次。
舉個具體的例子:
[code25]
for /l %%i in (1,2,10) do echo bathome
在以上的代碼中,初始值是1,步長爲2,終止值爲10,代表計數從1開始,每隔2個數計算一次,直至最接近10的那個整數,羅列出來,就是1,3,5,7,9,再下一個就是11,超過10了,再也不計算在內,因此,do後的語句只執行5次,將連續顯示5個bathome。
實際上,x,y和z的值可正可負,甚至爲0,限制很是寬鬆:
一、步長y的值不能爲0;
二、當步長y的值爲正整數時,終止值z不能小於初始值x;
三、當步長y的值爲負整數的時候,終止值z不能大於初始值x。
換而言之,必須保證in和do之間能取到一個有效的數組序列。
例如:
[code26]
for /l %%i in (-1,2,5) do echo bathome
[code27]
for /l %%i in (5,-2,-1) do echo bathome
以上兩條代碼的功能徹底同樣,都將顯示4次bathome,區別就在於[code26]是正序計算,而[code27]是逆序計數而已。
如下幾條代碼都是有問題的:
[code28]
for /l %%i in (1,0,1) do echo bathome
[code29]
for /l %%i in (2,1,1) do echo bathome
[code30]
for /l %%i in (1,-1,2) do echo bathome
其中,[code28]違反了步長不能爲0的限制,將陷入無限循環中;[code29]和[code30]都犯了一樣的錯誤:沒法得到有效的數列元素,致使in和do之間取到的值爲空元素,從而使得整條for語句無從執行。
當你們明白了 for /l 的具體功能以後,是否會想到了與它有殊途同歸之妙的goto循環語句呢?彷佛,for /l 和 goto 循環語句能夠相互替換?
通常而言,for /l語句能夠換成goto循環,可是,goto循環並不必定能被 for /l 語句替換掉。具體緣由,請你們仔細想一想,我在此再也不詳細解說,只是就你們很是關心的一個問題提供一個簡潔的答案,那就是:何時該用 for /l 計數循環,而何時又該用goto條件循環?
答案很是簡單:當循環次數肯定的時候,首選 for /l 語句,也可以使用goto語句但不推薦;當循環次數不肯定的時候,用goto語句將是惟一的選擇,由於,這個時候須要用if之類的條件語句來判斷什麼時候結束goto跳轉。
轉載:http://www.bathome.net/thread-2189-1-1.html