3.2.1 for循環(huán)語句

2022-04-13 15:07 更新

《批處理入門手冊》
三.批處理高級語句篇
-----------------------------------------------------------------------------------------------------
3.2.1 學(xué)習(xí)for循環(huán)語句

學(xué)習(xí)要點:
一.前言
二.for語句的基本用法
三.for /f  用法詳解
-----------------------------------------------------------------------------------------------------

    此文原文名為《for語句從入門到精通》,原文地址:http://bbs.bathome.cn/thread-2189-1-1.html

一、前言
  在批處理中,for是最為強大的命令語句,它的出現(xiàn),使得解析文本內(nèi)容、遍歷文件路徑、數(shù)值遞增/遞減等操作
成為可能;配合if、call、goto等流程控制語句,更是可以實現(xiàn)腳本復(fù)雜的自動化、智能化操作;合理使用for語句,
還能使代碼大為簡化,免除各位編寫大量重復(fù)語句之苦。而能否熟練使用for語句,已經(jīng)成為衡量一個人批處理水平高
低最主要的標(biāo)準(zhǔn)。
  在這個系列教程中,我將通過實際應(yīng)用中頻繁出現(xiàn)的例子,帶領(lǐng)大家步入for語句的神奇之門,一步步邁向for語
句的魔幻殿堂,使得大家在實際的應(yīng)用中,能獨立寫出簡潔高效的代碼,在批處理的世界里自由馳騁。
  注意:以下的講解,都是基于簡體中文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)境,是因為在這兩種環(huán)境下,命令語句表現(xiàn)出來的行為雖然基本一樣,
但是在細(xì)節(jié)上還是稍有不同,最明顯的一個差異就是:在cmd窗口中,for之后的形式變量I必須使用單百分號引用,
即%I;而在批處理文件中,引用形式變量I必須使用雙百分號,即%%I。為了方便起見,若不是特別強調(diào),以下的講解
都以批處理文件環(huán)境為例。

  我們先來看一下for語句的基本要素都有些什么:

  1、for、in和do是for語句的關(guān)鍵字,它們?nèi)齻€缺一不可;
  2、%%I是for語句中對形式變量的引用,就算它在do后的語句中沒有參與語句的執(zhí)行,也是必須出現(xiàn)的;
  3、in之后,do之前的括號不能省略;
  4、command1和command2表示字符串、變量或命令語句;

  現(xiàn)在,你可能已經(jīng)會寫一個簡單的for語句了,比如:

[code1]

@echo off
for %%I in (bbs.bathome.cn) do echo %%I
pause

  保存為批處理文件并執(zhí)行,將會在彈出的批處理窗口中看到這樣的信息:

[result1]

bbs.bathome.cn
請按任意鍵繼續(xù)...

  很快地,你會覺得這個for語句是如此的簡單,簡單到你絲毫感受不出它的強大:這個for語句,和我直接用echo
語句沒什么兩樣?。?/p>

  是的,演示代碼永遠(yuǎn)都只是演示而已,就像大多數(shù)高級語言的教科書一樣,在引導(dǎo)新手學(xué)習(xí)的時候,基本上都是
千篇一律地告訴大家如何編寫一個能顯示 hello world! 的窗口,從這些演示代碼中,你看不到它們具有多少實用性
,你只是感到有點好奇:咦,居然彈出了一個窗口?片刻之后,你就會覺得索然無味。

  那好吧,為了讓大家對for更加感興趣,我們先來分析一下for語句的一些注意事項,之后,再讓大家看看更為強
大的for語句實例。

  1、for語句的形式變量I,可以換成26個字母中的任意一個,這些字母會區(qū)分大小寫,也就是說,%%I和%%i會被
認(rèn)為不是同一個變量;形式變量I還可以換成其他的字符,但是,為了不與批處理中的%0~%9這10個形式變量發(fā)生沖
突,請不要隨意把%%I替換為%%0 ~%%9中的任意一個;
  2、in和do之間的command1表示的字符串或變量可以是一個,也可以是多個,每一個字符串或變量,我們稱之為
一個元素,每個元素之間,用空格鍵、跳格鍵、逗號、分號或等號分隔;
  3、for語句依次提取command1中的每一個元素,把它的值賦予形式變量I,帶到do后的command2中參與命令的執(zhí)行
;并且每次只提取一個元素,然后執(zhí)行一次do后的命令語句,而無論這個元素是否被帶到command2中參與了command2
的運行;當(dāng)執(zhí)行完一次do后的語句之后,再提取command1中的下一個元素,再執(zhí)行一次command2,如此循環(huán),直到
command1中的所有元素都已經(jīng)被提取完畢,該for語句才宣告執(zhí)行結(jié)束;

  其中,第3點是最為關(guān)鍵的,它描述了for語句的執(zhí)行過程,是for語句的精髓所在,大家一定要牢記這一條,才
能深刻理解更為復(fù)雜的for流程。

  有了以上的基礎(chǔ),我們再來看一個例子,這個例子修改了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、每一行都從逗號處被切分;

  如果把 bbs.bathome.cn 這個字符串中的點號換為空格、跳格或等號,執(zhí)行結(jié)果將和code2的執(zhí)行結(jié)果別無二致。

  現(xiàn)在,我們來分析一下code2代碼中for語句的執(zhí)行過程:

  首先,for語句以逗號為分隔符,把 bbs,bathome,cn 這個字符串切分成三個元素:bbs、bathome和cn,由此決
定了do后的語句將會被執(zhí)行3次;
  然后,第一次執(zhí)行過程是這樣的:先把 bbs 這個字符串作為形式變量I的值,帶入do后的語句中加以執(zhí)行,也就
是執(zhí)行 echo %%I 語句,此時的I值為bbs,因此,第一次執(zhí)行的結(jié)果,將會在屏幕上顯示bbs這個字符串;第二次執(zhí)
行和第一次執(zhí)行的過程是一樣的,只不過此時I的值已經(jīng)被替換為command1中的第二個元素了,也就是 bathome 這個
字符串;如此循環(huán),當(dāng)?shù)谌蝒cho執(zhí)行完畢之后,整條for語句才算執(zhí)行完畢,此時,將執(zhí)行下一條語句,也就是
pause命令。

  其實,這個例子只比上一個例子多了一點花樣,有趣了那么一點點:一條for語句的執(zhí)行結(jié)果居然被分成了3行!

  為了讓大家見識一下for的真正威力,本人絞盡腦汁,翻帖無數(shù),不得要領(lǐng),萬般無奈之下,只好亮出了塵封在
箱底多年的一段代碼:檢測當(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

  這段代碼能檢測硬盤都有哪些分區(qū),包括U盤和移動硬盤的分區(qū),但是,當(dāng)光驅(qū)中有盤的時候,也會被列出來,
這是本代碼的一個缺憾,在以后的講解中,我將向大家講述如何消除這個瑕疵,敬請關(guān)注本系列的后續(xù)章節(jié)。

  高級應(yīng)用:

  想知道當(dāng)前目錄下都有哪些文件嗎?請用下面的代碼:

@echo off
for %%i in (*.*) do echo "%%i"
pause

  想列出當(dāng)前目錄下所有的文本文件嗎?請用下面的代碼:

@echo off
for %%i in (*.txt) do echo "%%i"
pause

  想列出只用兩個字符作為文件名的文本文件嗎?請用下面的代碼:

@echo off
for %%i in (??.txt) do echo "%%i"
pause

  題外話:

  1、列出當(dāng)前目錄下各種文件的方法,最簡單的還是用dir命令,但是,從以上代碼中,各位可以加深對for語句
執(zhí)行流程的理解(用到了通配符*和?);
  2、注意:以上代碼不能列出含有隱藏或系統(tǒng)屬性的文件;

  練習(xí):用for語句建立test1.txt、test2.txt和test3.txt三個文本文件。

更全面的練習(xí)請看這個帖子:for語句從入門到精通配套練習(xí)題 http://bbs.bathome.cn/thread-2336-1-1.html
-----------------------------------------------------------------------------------------------------

 

三、文本解析顯神威:for /f 用法詳解[2009.2.10更新]
    前言

  for /f 是個十分強大的家伙。

  如果說,for語句是批處理中最強大的語句的話,那么,for /f 就是精華中的精華。

  for /f 的強大,和它擁有眾多的開關(guān)密切相關(guān)。因為開關(guān)眾多,所以用法復(fù)雜,本章將分成若干小節(jié),為大家
逐一介紹強大的 for /f 語句。
-----------------------------------------------------------------------------------------------------


(一) 為解析文本而生:for /f 的基本用法

  所有的對象,無論是文件、窗體、還是控件,在所有的非機器語言看來,無外乎都是形如"c:\test.txt"、"CWnd"
之類的文本信息;而所有的對象,具體的如ini文件中的某條配置信息、注冊表中的某個鍵
值、數(shù)據(jù)庫中的某條記錄……都只有轉(zhuǎn)化為具有一定格式的文本信息,方可被代碼識別、操控??梢哉f,編程的很大
一部分工作,都是在想方設(shè)法絞盡腦汁如何提取這些文本信息。

  而提取文本信息,則是for /f的拿手好戲:讀取文件內(nèi)容;提取某幾行字符;截取某個字符片段;對提取到的內(nèi)
容再切分、打亂、雜糅……只要你所能想到的花樣,for /f 都會想方設(shè)法幫你辦到,因為,for /f 就是被設(shè)計成專
門用于解析文本的。

  先來看個例子。

  假如有個文本文件test.txt,內(nèi)容如下:
[txt1]

論壇的目標(biāo)是:不求最大,但求最好,做最實用的批處理論壇。
論壇地址:bbs.bathome.cn。
這里是:新手晉級的福地,高手論劍的天堂?! ?/p>

那么,將如下代碼保存為test.cmd,并放在test.txt同一目錄下運行,將會在屏幕上原樣顯示test.txt的內(nèi)容:

[code4]

@echo off
for /f %%i in (test.txt) do echo %%i
pause  

這段代碼,主要是讓你樹立這樣一種觀念:讀取文本文件的內(nèi)容,請使用 for /f 語句!

  進階話題:for /f 語句是把整個test.txt一次性顯示出來的?

  在這段代碼中,雖然執(zhí)行結(jié)果是把test.txt中的所有內(nèi)容都顯示出來了,貌似 for /f 語句是把整個test.txt一
次性顯示到屏幕上,實際上并非如此。

  無論for語句做何種變化,它的執(zhí)行過程仍然遵循基本的for流程:依次處理每個元素,直到所有的元素都被處理
為止。只不過在for /f語句中,這里的元素是指文件中的每一行,也就是說,for /f 語句是以行為單位處理文本文
件的。這是一條極為重要的規(guī)則,在上一章中也強調(diào)過它的重要性,希望在接下來的學(xué)習(xí)過程中,你能時刻牢記這一
原則,那么,很多問題將會迎刃而解。以下是驗證這一說法的演示代碼(在[code4]的基礎(chǔ)上添加了&pause語句):
[code5]

@echo off
for /f %%i in (test.txt) do echo %%i&pause
pause    
-----------------------------------------------------------------------------------------------------


(二) 切分字符串的利器:delims=

  也許你對[code4]這段代碼不屑一顧:不就是把test.txt的內(nèi)容顯示出來了么?好像用處不大啊。

  好吧,我們來玩?zhèn)€魔術(shù)。

  還是[txt1]這段文本,把[code4]改造一下:
[code6]

@echo off
for /f "delims=," %%i in (test.txt) do echo %%i
pause  

再次運行test.cmd,看到什么變化了嗎?!
[result2]

論壇的目標(biāo)是:不求最大
論壇地址:bbs.bathome.cn。
這里是:新手晉級的福地
請按任意鍵繼續(xù)...  

結(jié)果,你驚奇地發(fā)現(xiàn),每行第一個逗號之后的所有內(nèi)容都不見了(如果有不存在逗號的行,則保留原樣),也就說,
你成功地提取到了每行第一個逗號之前的所有內(nèi)容!

  試想一下,這段代碼會有什么用呢?

  如果別人給了你一個軟件清單,每行都是"英文軟件名(逗號)中文軟件名"的格式,而你卻只想保留英文名的時
候,這段代碼將是多么有用??!再假設(shè),有這么一個IP文件,第一列是數(shù)字格式的IP地址,第二列是具體的空間地址
,列與列之間用逗號分隔,而你想提取其中數(shù)字格式的IP,呵呵,我不說你也知道該怎么辦了吧?

  要是文本內(nèi)容不是以逗號分隔,而是以其他符號分隔,那么,把"delims=,"的逗號換成相應(yīng)的符號就可以了。

  在這里,我們引入了一個新的開關(guān):"delims=,",它的含義是:以逗號作為被處理的字符串的分隔符號。

  在批處理中,指定分隔符號的方法是:添加一個形如 "delims=符號列表" 的開關(guān),這樣,被處理的每行字符串
都會被符號列表中羅列出來的符號切分開來。

  需要注意的是:如果沒有指定"delims=符號列表"這個開關(guān),那么,for /f 語句默認(rèn)以空格鍵或跳格鍵作為分隔
符號。請把[txt1]中不同位置上的標(biāo)點符號改為空格或跳格,再運行[code4]試試。

  進階話題:如果我要指定的符號不止一個,該怎么辦?

  在上面的講解中,我提到了指定分隔符號的方法:添加一個形如"delims=符號列表"的開關(guān)。不知道你注意到?jīng)]
有,我的說法是"符號列表"而非"符號",這是大有講究的,因為,你可以一次性指定多個分隔符號!

  還是以[txt1]為例,把[code6]再改造一下:
[code7]

@echo off
for /f "delims=.," %%i in (test.txt) do echo %%i
pause  

結(jié)果顯示:
[result3]

論壇的目標(biāo)是:不求最大
論壇地址:bbs
這里是:新手晉級的福地
請按任意鍵繼續(xù)...  

這樣,第一個點號或第一個逗號之前的內(nèi)容都被提取出來了。

  [code7]的執(zhí)行過程是:逐行讀取test.txt中的內(nèi)容,以點號和逗號切分每一行的內(nèi)容(不存在點號和逗號的行
,則不再切分,為了描述的方便,我們把被點號或逗號切分的一個一個的字符串片段,稱之為節(jié)),然后,for /f
會提取第一節(jié)的內(nèi)容作為最終結(jié)果,顯示在屏幕上。需要注意的是,在這里,所有行的字符串被切分成了兩個以上的
節(jié),但是,[code7]的代碼只會提取第一節(jié)字符串的內(nèi)容,因為 for /f 語句默認(rèn)只提取第一節(jié)的符串。

 

以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號