《批處理入門手冊(cè)》
三.批處理高級(jí)語句篇
-----------------------------------------------------------------------------------------------------
3.2.1 學(xué)習(xí)for循環(huán)語句
學(xué)習(xí)要點(diǎn):
一.前言
二.for語句的基本用法
三.for /f 用法詳解
-----------------------------------------------------------------------------------------------------
此文原文名為《for語句從入門到精通》,原文地址:http://bbs.bathome.cn/thread-2189-1-1.html
一、前言
在批處理中,for是最為強(qiáng)大的命令語句,它的出現(xiàn),使得解析文本內(nèi)容、遍歷文件路徑、數(shù)值遞增/遞減等操作
成為可能;配合if、call、goto等流程控制語句,更是可以實(shí)現(xiàn)腳本復(fù)雜的自動(dòng)化、智能化操作;合理使用for語句,
還能使代碼大為簡(jiǎn)化,免除各位編寫大量重復(fù)語句之苦。而能否熟練使用for語句,已經(jīng)成為衡量一個(gè)人批處理水平高
低最主要的標(biāo)準(zhǔn)。
在這個(gè)系列教程中,我將通過實(shí)際應(yīng)用中頻繁出現(xiàn)的例子,帶領(lǐng)大家步入for語句的神奇之門,一步步邁向for語
句的魔幻殿堂,使得大家在實(shí)際的應(yīng)用中,能獨(dú)立寫出簡(jiǎn)潔高效的代碼,在批處理的世界里自由馳騁。
注意:以下的講解,都是基于簡(jiǎn)體中文Windows XP Pro SP3的操作系統(tǒng)環(huán)境
-----------------------------------------------------------------------------------------------------
二、for語句的基本用法[2008.11.9更新]
正如色彩繽紛的七彩光芒是由紅綠藍(lán)三原色構(gòu)成的一樣,最復(fù)雜的for語句,也有其基本形態(tài),它的模樣是這樣
的:
在cmd窗口中:for %I in (command1) do command2
(高版本的Windows 命令提示符不支持上面的寫法)
在批處理文件中:for %%I in (command1) do command2
之所以要區(qū)分cmd窗口和批處理文件兩種環(huán)境,是因?yàn)樵谶@兩種環(huán)境下,命令語句表現(xiàn)出來的行為雖然基本一樣,
但是在細(xì)節(jié)上還是稍有不同,最明顯的一個(gè)差異就是:在cmd窗口中,for之后的形式變量I必須使用單百分號(hào)引用,
即%I;而在批處理文件中,引用形式變量I必須使用雙百分號(hào),即%%I。為了方便起見,若不是特別強(qiáng)調(diào),以下的講解
都以批處理文件環(huán)境為例。
我們先來看一下for語句的基本要素都有些什么:
1、for、in和do是for語句的關(guān)鍵字,它們?nèi)齻€(gè)缺一不可;
2、%%I是for語句中對(duì)形式變量的引用,就算它在do后的語句中沒有參與語句的執(zhí)行,也是必須出現(xiàn)的;
3、in之后,do之前的括號(hào)不能省略;
4、command1和command2表示字符串、變量或命令語句;
現(xiàn)在,你可能已經(jīng)會(huì)寫一個(gè)簡(jiǎn)單的for語句了,比如:
[code1]
@echo off
for %%I in (bbs.bathome.cn) do echo %%I
pause
保存為批處理文件并執(zhí)行,將會(huì)在彈出的批處理窗口中看到這樣的信息:
[result1]
bbs.bathome.cn
請(qǐng)按任意鍵繼續(xù)...
很快地,你會(huì)覺得這個(gè)for語句是如此的簡(jiǎn)單,簡(jiǎn)單到你絲毫感受不出它的強(qiáng)大:這個(gè)for語句,和我直接用echo
語句沒什么兩樣啊!
是的,演示代碼永遠(yuǎn)都只是演示而已,就像大多數(shù)高級(jí)語言的教科書一樣,在引導(dǎo)新手學(xué)習(xí)的時(shí)候,基本上都是
千篇一律地告訴大家如何編寫一個(gè)能顯示 hello world! 的窗口,從這些演示代碼中,你看不到它們具有多少實(shí)用性
,你只是感到有點(diǎn)好奇:咦,居然彈出了一個(gè)窗口?片刻之后,你就會(huì)覺得索然無味。
那好吧,為了讓大家對(duì)for更加感興趣,我們先來分析一下for語句的一些注意事項(xiàng),之后,再讓大家看看更為強(qiáng)
大的for語句實(shí)例。
1、for語句的形式變量I,可以換成26個(gè)字母中的任意一個(gè),這些字母會(huì)區(qū)分大小寫,也就是說,%%I和%%i會(huì)被
認(rèn)為不是同一個(gè)變量;形式變量I還可以換成其他的字符,但是,為了不與批處理中的%0~%9這10個(gè)形式變量發(fā)生沖
突,請(qǐng)不要隨意把%%I替換為%%0 ~%%9中的任意一個(gè);
2、in和do之間的command1表示的字符串或變量可以是一個(gè),也可以是多個(gè),每一個(gè)字符串或變量,我們稱之為
一個(gè)元素,每個(gè)元素之間,用空格鍵、跳格鍵、逗號(hào)、分號(hào)或等號(hào)分隔;
3、for語句依次提取command1中的每一個(gè)元素,把它的值賦予形式變量I,帶到do后的command2中參與命令的執(zhí)行
;并且每次只提取一個(gè)元素,然后執(zhí)行一次do后的命令語句,而無論這個(gè)元素是否被帶到command2中參與了command2
的運(yùn)行;當(dāng)執(zhí)行完一次do后的語句之后,再提取command1中的下一個(gè)元素,再執(zhí)行一次command2,如此循環(huán),直到
command1中的所有元素都已經(jīng)被提取完畢,該for語句才宣告執(zhí)行結(jié)束;
其中,第3點(diǎn)是最為關(guān)鍵的,它描述了for語句的執(zhí)行過程,是for語句的精髓所在,大家一定要牢記這一條,才
能深刻理解更為復(fù)雜的for流程。
有了以上的基礎(chǔ),我們?cè)賮砜匆粋€(gè)例子,這個(gè)例子修改了code1的部分內(nèi)容,結(jié)果將大不一樣:
[code2]
@echo off
for %%I in (bbs,bathome,cn) do echo %%I
pause
和[code1]的執(zhí)行結(jié)果相比,[code2]的執(zhí)行結(jié)果發(fā)生了如下變化:
1、顯示結(jié)果分成了3行(不算最后一行中文提示);
2、每一行都從逗號(hào)處被切分;
如果把 bbs.bathome.cn 這個(gè)字符串中的點(diǎn)號(hào)換為空格、跳格或等號(hào),執(zhí)行結(jié)果將和code2的執(zhí)行結(jié)果別無二致。
現(xiàn)在,我們來分析一下code2代碼中for語句的執(zhí)行過程:
首先,for語句以逗號(hào)為分隔符,把 bbs,bathome,cn 這個(gè)字符串切分成三個(gè)元素:bbs、bathome和cn,由此決
定了do后的語句將會(huì)被執(zhí)行3次;
然后,第一次執(zhí)行過程是這樣的:先把 bbs 這個(gè)字符串作為形式變量I的值,帶入do后的語句中加以執(zhí)行,也就
是執(zhí)行 echo %%I 語句,此時(shí)的I值為bbs,因此,第一次執(zhí)行的結(jié)果,將會(huì)在屏幕上顯示bbs這個(gè)字符串;第二次執(zhí)
行和第一次執(zhí)行的過程是一樣的,只不過此時(shí)I的值已經(jīng)被替換為command1中的第二個(gè)元素了,也就是 bathome 這個(gè)
字符串;如此循環(huán),當(dāng)?shù)谌蝒cho執(zhí)行完畢之后,整條for語句才算執(zhí)行完畢,此時(shí),將執(zhí)行下一條語句,也就是
pause命令。
其實(shí),這個(gè)例子只比上一個(gè)例子多了一點(diǎn)花樣,有趣了那么一點(diǎn)點(diǎn):一條for語句的執(zhí)行結(jié)果居然被分成了3行!
為了讓大家見識(shí)一下for的真正威力,本人絞盡腦汁,翻帖無數(shù),不得要領(lǐng),萬般無奈之下,只好亮出了塵封在
箱底多年的一段代碼:檢測(cè)當(dāng)前硬盤都有哪些分區(qū)^_^
[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 當(dāng)前硬盤的分區(qū)有:
for %%i in (%str%) do if exist %%i: echo %%i:
pause
這段代碼能檢測(cè)硬盤都有哪些分區(qū),包括U盤和移動(dòng)硬盤的分區(qū),但是,當(dāng)光驅(qū)中有盤的時(shí)候,也會(huì)被列出來,
這是本代碼的一個(gè)缺憾,在以后的講解中,我將向大家講述如何消除這個(gè)瑕疵,敬請(qǐng)關(guān)注本系列的后續(xù)章節(jié)。
高級(jí)應(yīng)用:
想知道當(dāng)前目錄下都有哪些文件嗎?請(qǐng)用下面的代碼:
@echo off
for %%i in (*.*) do echo "%%i"
pause
想列出當(dāng)前目錄下所有的文本文件嗎?請(qǐng)用下面的代碼:
@echo off
for %%i in (*.txt) do echo "%%i"
pause
想列出只用兩個(gè)字符作為文件名的文本文件嗎?請(qǐng)用下面的代碼:
@echo off
for %%i in (??.txt) do echo "%%i"
pause
題外話:
1、列出當(dāng)前目錄下各種文件的方法,最簡(jiǎn)單的還是用dir命令,但是,從以上代碼中,各位可以加深對(duì)for語句
執(zhí)行流程的理解(用到了通配符*和?);
2、注意:以上代碼不能列出含有隱藏或系統(tǒng)屬性的文件;
練習(xí):用for語句建立test1.txt、test2.txt和test3.txt三個(gè)文本文件。
更全面的練習(xí)請(qǐng)看這個(gè)帖子:for語句從入門到精通配套練習(xí)題 http://bbs.bathome.cn/thread-2336-1-1.html
-----------------------------------------------------------------------------------------------------
三、文本解析顯神威:for /f 用法詳解[2009.2.10更新]
前言
for /f 是個(gè)十分強(qiáng)大的家伙。
如果說,for語句是批處理中最強(qiáng)大的語句的話,那么,for /f 就是精華中的精華。
for /f 的強(qiáng)大,和它擁有眾多的開關(guān)密切相關(guān)。因?yàn)殚_關(guān)眾多,所以用法復(fù)雜,本章將分成若干小節(jié),為大家
逐一介紹強(qiáng)大的 for /f 語句。
-----------------------------------------------------------------------------------------------------
(一) 為解析文本而生:for /f 的基本用法
所有的對(duì)象,無論是文件、窗體、還是控件,在所有的非機(jī)器語言看來,無外乎都是形如"c:\test.txt"、"CWnd"
之類的文本信息;而所有的對(duì)象,具體的如ini文件中的某條配置信息、注冊(cè)表中的某個(gè)鍵
值、數(shù)據(jù)庫中的某條記錄……都只有轉(zhuǎn)化為具有一定格式的文本信息,方可被代碼識(shí)別、操控。可以說,編程的很大
一部分工作,都是在想方設(shè)法絞盡腦汁如何提取這些文本信息。
而提取文本信息,則是for /f的拿手好戲:讀取文件內(nèi)容;提取某幾行字符;截取某個(gè)字符片段;對(duì)提取到的內(nèi)
容再切分、打亂、雜糅……只要你所能想到的花樣,for /f 都會(huì)想方設(shè)法幫你辦到,因?yàn)?,for /f 就是被設(shè)計(jì)成專
門用于解析文本的。
先來看個(gè)例子。
假如有個(gè)文本文件test.txt,內(nèi)容如下:
[txt1]
論壇的目標(biāo)是:不求最大,但求最好,做最實(shí)用的批處理論壇。
論壇地址:bbs.bathome.cn。
這里是:新手晉級(jí)的福地,高手論劍的天堂。
那么,將如下代碼保存為test.cmd,并放在test.txt同一目錄下運(yùn)行,將會(huì)在屏幕上原樣顯示test.txt的內(nèi)容:
[code4]
@echo off
for /f %%i in (test.txt) do echo %%i
pause
這段代碼,主要是讓你樹立這樣一種觀念:讀取文本文件的內(nèi)容,請(qǐng)使用 for /f 語句!
進(jìn)階話題:for /f 語句是把整個(gè)test.txt一次性顯示出來的?
在這段代碼中,雖然執(zhí)行結(jié)果是把test.txt中的所有內(nèi)容都顯示出來了,貌似 for /f 語句是把整個(gè)test.txt一
次性顯示到屏幕上,實(shí)際上并非如此。
無論for語句做何種變化,它的執(zhí)行過程仍然遵循基本的for流程:依次處理每個(gè)元素,直到所有的元素都被處理
為止。只不過在for /f語句中,這里的元素是指文件中的每一行,也就是說,for /f 語句是以行為單位處理文本文
件的。這是一條極為重要的規(guī)則,在上一章中也強(qiáng)調(diào)過它的重要性,希望在接下來的學(xué)習(xí)過程中,你能時(shí)刻牢記這一
原則,那么,很多問題將會(huì)迎刃而解。以下是驗(yàn)證這一說法的演示代碼(在[code4]的基礎(chǔ)上添加了&pause語句):
[code5]
@echo off
for /f %%i in (test.txt) do echo %%i&pause
pause
-----------------------------------------------------------------------------------------------------
(二) 切分字符串的利器:delims=
也許你對(duì)[code4]這段代碼不屑一顧:不就是把test.txt的內(nèi)容顯示出來了么?好像用處不大啊。
好吧,我們來玩?zhèn)€魔術(shù)。
還是[txt1]這段文本,把[code4]改造一下:
[code6]
@echo off
for /f "delims=," %%i in (test.txt) do echo %%i
pause
再次運(yùn)行test.cmd,看到什么變化了嗎?!
[result2]
論壇的目標(biāo)是:不求最大
論壇地址:bbs.bathome.cn。
這里是:新手晉級(jí)的福地
請(qǐng)按任意鍵繼續(xù)...
結(jié)果,你驚奇地發(fā)現(xiàn),每行第一個(gè)逗號(hào)之后的所有內(nèi)容都不見了(如果有不存在逗號(hào)的行,則保留原樣),也就說,
你成功地提取到了每行第一個(gè)逗號(hào)之前的所有內(nèi)容!
試想一下,這段代碼會(huì)有什么用呢?
如果別人給了你一個(gè)軟件清單,每行都是"英文軟件名(逗號(hào))中文軟件名"的格式,而你卻只想保留英文名的時(shí)
候,這段代碼將是多么有用?。≡偌僭O(shè),有這么一個(gè)IP文件,第一列是數(shù)字格式的IP地址,第二列是具體的空間地址
,列與列之間用逗號(hào)分隔,而你想提取其中數(shù)字格式的IP,呵呵,我不說你也知道該怎么辦了吧?
要是文本內(nèi)容不是以逗號(hào)分隔,而是以其他符號(hào)分隔,那么,把"delims=,"的逗號(hào)換成相應(yīng)的符號(hào)就可以了。
在這里,我們引入了一個(gè)新的開關(guān):"delims=,",它的含義是:以逗號(hào)作為被處理的字符串的分隔符號(hào)。
在批處理中,指定分隔符號(hào)的方法是:添加一個(gè)形如 "delims=符號(hào)列表" 的開關(guān),這樣,被處理的每行字符串
都會(huì)被符號(hào)列表中羅列出來的符號(hào)切分開來。
需要注意的是:如果沒有指定"delims=符號(hào)列表"這個(gè)開關(guān),那么,for /f 語句默認(rèn)以空格鍵或跳格鍵作為分隔
符號(hào)。請(qǐng)把[txt1]中不同位置上的標(biāo)點(diǎn)符號(hào)改為空格或跳格,再運(yùn)行[code4]試試。
進(jìn)階話題:如果我要指定的符號(hào)不止一個(gè),該怎么辦?
在上面的講解中,我提到了指定分隔符號(hào)的方法:添加一個(gè)形如"delims=符號(hào)列表"的開關(guān)。不知道你注意到?jīng)]
有,我的說法是"符號(hào)列表"而非"符號(hào)",這是大有講究的,因?yàn)椋憧梢砸淮涡灾付ǘ鄠€(gè)分隔符號(hào)!
還是以[txt1]為例,把[code6]再改造一下:
[code7]
@echo off
for /f "delims=.," %%i in (test.txt) do echo %%i
pause
結(jié)果顯示:
[result3]
論壇的目標(biāo)是:不求最大
論壇地址:bbs
這里是:新手晉級(jí)的福地
請(qǐng)按任意鍵繼續(xù)...
這樣,第一個(gè)點(diǎn)號(hào)或第一個(gè)逗號(hào)之前的內(nèi)容都被提取出來了。
[code7]的執(zhí)行過程是:逐行讀取test.txt中的內(nèi)容,以點(diǎn)號(hào)和逗號(hào)切分每一行的內(nèi)容(不存在點(diǎn)號(hào)和逗號(hào)的行
,則不再切分,為了描述的方便,我們把被點(diǎn)號(hào)或逗號(hào)切分的一個(gè)一個(gè)的字符串片段,稱之為節(jié)),然后,for /f
會(huì)提取第一節(jié)的內(nèi)容作為最終結(jié)果,顯示在屏幕上。需要注意的是,在這里,所有行的字符串被切分成了兩個(gè)以上的
節(jié),但是,[code7]的代碼只會(huì)提取第一節(jié)字符串的內(nèi)容,因?yàn)?for /f 語句默認(rèn)只提取第一節(jié)的符串。
更多建議: