4 條件 循環(huán)
4.1 條件 if
4.1.1 if 是一種極其普遍卻又非常重要的語(yǔ)句,說(shuō)得嚴(yán)重點(diǎn)這就是一種能夠體現(xiàn)程序靈魂的東西之一。在大多數(shù)的編程語(yǔ)言(例如 C VB JScript Java 等)中都能看到 if 的身影。if 語(yǔ)句的功能正如它的字面含義一樣——如果。批處理程序的語(yǔ)言格式相比較我們常見(jiàn)的 C 語(yǔ)言來(lái)說(shuō),并不是那么的嚴(yán)謹(jǐn),至少看上去是更自由一些。比如 if 在批處理中的具體用法及格式就有很多,使用和發(fā)揮的余地也很大,但隨之帶來(lái)的問(wèn)題就是我們不得不多花一些時(shí)間來(lái)記憶其各種用法和格式并分辨它們之間的差異。為了簡(jiǎn)化該問(wèn)題使之更容易理解,在此我們并不打算過(guò)早地接觸 if 的全面用法或格式,而是從最基本的用途開(kāi)始。
4.1.2 在有前幾篇文章的學(xué)習(xí)作基礎(chǔ)的情況下,如果您能理解以下幾行語(yǔ)句,那么您已經(jīng)對(duì) if 有了深刻的認(rèn)識(shí)了(其中兩個(gè)連續(xù)的等號(hào) == 表示:是否等于)。
set var=Tom
if %var%==Tom echo It works
if %var%==Jerry echo We will never see this
如果變量 var 的值為 Tom Hanks ,即中間含有空格之類的特殊符號(hào),那么我們?cè)谑褂?if 時(shí),就得為字符串加上雙引號(hào),就像 if "%var%"=="Tom Hanks" echo It works (注意,給字符串加上雙引號(hào)后,在進(jìn)行判斷的時(shí)候會(huì)連雙引號(hào)一起考慮進(jìn)去。所以,為了使兩邊的對(duì)比均衡,所以一定要在 == 兩邊的兩個(gè)字符串上同時(shí)都加雙引號(hào))。這里也體現(xiàn)了批處理程序語(yǔ)言格式的多樣性(如果您熟悉 C 語(yǔ)言格式的話,就知道一串字符總是要被雙引號(hào)引起來(lái))。不過(guò)為了方便記憶,我們?cè)谑褂?if 的時(shí)候,不妨總是在字符串上使用雙引號(hào),這樣既好閱讀,又不容易引起歧異。
::::::::::改變顏色.bat::::::::::
@echo off
echo 您希望字體的顏色是紅色還是綠色?
:RETRY
set /p choice=請(qǐng)輸入您的選擇,R 或者 G :
if "%choice%"=="R" goto R
if "%choice%"=="r" goto R
if "%choice%"=="G" goto G
if "%choice%"=="g" goto G
goto RETRY
:R
color c
echo 您選擇了紅色字體
pause
exit
:G
color a
echo 您選擇了綠色字體
pause
exit
::::::::::::::::::::::::::::::::
上面的例子能很好地說(shuō)明了 if 與 goto 的結(jié)合使用帶來(lái)的實(shí)用效果。其中,在使用 if 進(jìn)行判斷變量 choice 的值是否為字母 R 或 G 時(shí),分別對(duì)其大小寫都進(jìn)行了判斷。其實(shí)您還可以使用 if 的參數(shù) /i ,就像 if /i "%choice%"=="r" ,這樣在進(jìn)行比較的時(shí)候就不區(qū)分大小寫了。
4.1.3 說(shuō)到了 if 就不得不說(shuō)一下 else ,else 無(wú)法單獨(dú)使用,必須與 if 配合連用。
:::::::::else的用法.bat:::::::::
@echo off
if "%TIME:~0,2%" lss "12" (
echo 現(xiàn)在是上午
) else (
echo 現(xiàn)在是下午
)
pause
::::::::::::::::::::::::::::::::
其中,變量 TIME 是動(dòng)態(tài)環(huán)境變量之一,表示當(dāng)前時(shí)間(在 set/? 中有介紹)。%TIME:~0,2% 的含義還沒(méi)忘記吧,意思是取變量 TIME 的前兩個(gè)字符(忘記的朋友請(qǐng)參閱上一篇[賦值 調(diào)用 參數(shù)])。lss 是 if 命令擴(kuò)展用法,表示 小于 的意思。此外,還有等于、不等于、大于、大于等于、小于等于 的縮寫,詳細(xì)信息可以在 if/? 中獲得。因此,對(duì)于上述批處理的理解就是:如果當(dāng)前時(shí)間(前兩位表示小時(shí))小于12(點(diǎn))的話,那么將顯示輸出“現(xiàn)在是上午”,否則就顯示為“現(xiàn)在是下午”。另外:這里的大小比較判斷只是對(duì)其ASCII符的大小比較,并不是真正的數(shù)值型變量的比較,稍后下文會(huì)有關(guān)于數(shù)值型變量比較的介紹。
對(duì)于 if 和 else 的編寫格式有較嚴(yán)格的要求,尤其是在兩個(gè)圓括號(hào)上,若以不正確的格式使用可能會(huì)導(dǎo)致 if 或 else 等命令無(wú)效。雖然上面的編寫格式并不是唯一的,但使用統(tǒng)一、固定的格式編寫代碼會(huì)大大提高代碼的可讀性。為了加深對(duì) if else 的理解,我們可以把上面的批處理擴(kuò)展一下。
:::::::::else的用法.bat:::::::::
@echo off
if "%TIME:~0,2%" lss "12" (
if "%TIME:~0,2%" lss " 6" (
echo 現(xiàn)在是凌晨
) else (
echo 現(xiàn)在是上午
)
) else (
if "%TIME:~0,2%" lss "18" (
echo 現(xiàn)在是下午
) else (
echo 現(xiàn)在是晚上
)
)
pause
::::::::::::::::::::::::::::::::
4.1.4 剛才提到的數(shù)值型變量的比較,其實(shí)很簡(jiǎn)單,就如下面的例子中描述的一樣。
::::::::::::::::::::::::::::::::
@echo off
set /a num=5
if %num% == 5 (
echo 變量 num 等于 5
)
if not %num% == 4 (
echo 變量 num 不等于 4
)
set /a num = ( %num% + 3 ) * 2
:: 變量 num 加3并乘2后再賦給變量 num 自身
if %num% == 16 (
echo 經(jīng)過(guò)運(yùn)算后,現(xiàn)在變量 num 等于16
)
if not %num% == 16 (
echo 此時(shí)的變量 num 不會(huì)不等于 16 ,因此這一句不會(huì)顯示了
)
pause
::::::::::::::::::::::::::::::::
4.1.5 延遲變量擴(kuò)充。考慮到讀取一行文本時(shí)所遇到的目前擴(kuò)充的限制時(shí),延遲變量擴(kuò)充是很有用的,而不是在執(zhí)行的時(shí)候。下面的例子可以很好的說(shuō)明直接變量擴(kuò)充與延遲變量擴(kuò)充的區(qū)別。
::::::::延遲變量擴(kuò)充.bat::::::::
@echo off
setlocal EnableDelayedExpansion
set /a num=5
if %num% == 5 (
set /a num*=3
echo 在 if 語(yǔ)句之前,變量 num 等于 %num%
echo 但變量 num 在經(jīng)過(guò)運(yùn)算后,且由于延遲變量擴(kuò)充被啟用,變量 num 等于 !num!
)
echo 但最終變量 num 還是等于 %num%
pause
::::::::::::::::::::::::::::::::
if 條件下的兩行 echo 在輸出變量值的時(shí)候用到的符號(hào)不一樣,一個(gè)是用百分號(hào) % 包括起來(lái)的,另一個(gè)用的卻是驚嘆號(hào) ! 。雖然在顯示 %num% 之前已經(jīng)使變量 num 的數(shù)值乘了3倍,但是由于沒(méi)有延遲變量的擴(kuò)充,使得 %num% 的結(jié)果仍然是 5 。但用 !num! 顯示出的值已經(jīng)變?yōu)?15 了。注意到批處理中的 setlocal EnableDelayedExpansion (setlocal/? 查看相關(guān)信息),這表示開(kāi)啟延遲變量擴(kuò)充。此時(shí)的 !num! 才有意義。不然 !num! 將無(wú)法被識(shí)別,因?yàn)樵谀J(rèn)情況下,延遲變量擴(kuò)充是被停用的。
4.1.6 此外,if 還有其他的用法—— if exist 和 if defined 。if exist 可判斷文件是否存在,就像這樣:
if exist "D:\test my folder\a.txt" (
del "D:\test my folder\a.txt"
) else (
echo 您所要?jiǎng)h除的文件不存在
)
在對(duì)文件進(jìn)行操作之前進(jìn)行判斷其是否存在很有意義,這使得代碼更加健壯。
而對(duì)于 if defined 來(lái)說(shuō),與 if exist 類似,只不過(guò) if defined 的判斷對(duì)象不是文件,而是變量,它用于判斷環(huán)境變量是否被定義。
4.2 循環(huán) for
4.2.1 如果批處理不具備批量處理的功能,那么它就徒有虛名了。而命令 for ,在某種意義上徹底體現(xiàn)出了批處理的強(qiáng)大快捷省事批量的作用。在看過(guò) for/? 后,可以歸納出 for 大致可以分三種常用的類型(或者叫使用方法)。從針對(duì)的循環(huán)目標(biāo)來(lái)看,它們分別是針對(duì)于文件、數(shù)字、以及文字。
4.2.2 for %i in (*.*) do @echo %i 。這就是 for 的一般使用格式。注意到其中的淺靛色文字 for 、in 和 do ,是 for 的固定用法。其內(nèi)容可以理解為:在某一范圍內(nèi)(in),對(duì)于其中的某一文件來(lái)說(shuō)(for),做如下的處理(do)。而 for %i in (*.*) do @echo %i 就是在當(dāng)前工作目錄的所有文件中(in (*.*)),對(duì)于其中的某一文件(for %i),做出顯示其名稱的處理(do @echo %i)。變量 i 僅在當(dāng)前循環(huán)語(yǔ)句 for 里起作用,%i 表示其值。
注意:以上是直接在命令提示符里以命令的形式表達(dá)出來(lái)的寫法;在批處理文件中應(yīng)使用雙百分號(hào) %% 代替單百分比號(hào) % ,就像:%%i。關(guān)于它們之間的區(qū)別我研究了好半天才分清楚 orz [具體請(qǐng)參閱后文第4.2.5節(jié)]。
批量修改文件名是其比較有用的典例之一??纯聪旅娴呐幚?br>:::::::批量修改文件名.bat:::::::
@echo off
setlocal EnableDelayedExpansion
set /a num=1
for %%i in (D:\test\*.txt) do (
ren "%%i" !num!.txt
set /a num+=1
)
::::::::::::::::::::::::::::::::
這個(gè)批處理并不難理解。就像第4.1.5節(jié)所說(shuō)的:使用了 setlocal EnableDelayedExpansion 后,可以讓 for 或 if 后面的執(zhí)行語(yǔ)句中變量的值隨其變化而不斷更新(所以后面使用了 !num! 而不是 %num%)。整個(gè)批處理的處理過(guò)程就是對(duì) D:\test\*.txt 中的所有文本文件進(jìn)行批量改名,文件名從 1.txt 開(kāi)始依次為 2.txt 、3.txt ……。
注意:請(qǐng)確保循環(huán)語(yǔ)句 in 路徑中的文件不是重要的文件,因?yàn)楦拿髮o(wú)法使用撤消,如果像我一樣不小心把重要文件誤改名的話就又要 orz 了一次。
以上批處理是固定了文件的路徑以及文件后綴名。為了增加該批處理的功能,我們可以讓用戶自己選擇要進(jìn)行改名的文件所在路徑,以及選擇所進(jìn)行文件修改的后綴名。當(dāng)然,有些朋友還希望有給文件批量加上前綴(比如:前綴1.txt 前綴2.txt 等等)。(關(guān)于 批量改文件名.bat 在第六章中還有進(jìn)一步的修改)
::::::::批量改文件名.bat::::::::
@echo off
setlocal EnableDelayedExpansion
set /p zpath=請(qǐng)輸入目標(biāo)文件所在的路徑:
set /p prefix=請(qǐng)輸入文件名前綴(不能包含以下字符\/:*?"<>|):
set /p ext=請(qǐng)輸入文件的擴(kuò)展名(例如 .txt):
set /a num=1
for %%i in (%zpath%\*%ext%) do (
ren "%%i" "%prefix%!num!.%ext%"
set /a num+=1
)
::::::::::::::::::::::::::::::::
4.2.3 也許大家注意到了,上面 for 的用法僅僅是針對(duì)多個(gè)文件來(lái)進(jìn)行循環(huán)重復(fù)操作的。如果想對(duì)一系列有規(guī)律的數(shù)字進(jìn)行循環(huán),或是在一定的次數(shù)內(nèi)對(duì)某個(gè)操作進(jìn)行循環(huán)重復(fù)的執(zhí)行,使用 for 也能夠?qū)崿F(xiàn)。/l 是可以跟在 for 后面的重要參數(shù)之一。比如:for /l %i in (5,3,16) do echo %i ,可以讓數(shù)值型的變量 i 依次成為:5、8、11、14 。正如 in 里所描述的規(guī)律 (5,3,16) 一樣,從 5 開(kāi)始,每次增加 3 ,直到 16為止。同樣,我們還可以試一下 for /l %i in (19,-4,3) do echo %i ,這次 i 是遞減的規(guī)律。很明顯,結(jié)果將依次顯示為:19、15、11、7、3 。
這樣的用法很自然的能讓我們想到,重復(fù)執(zhí)行N遍完全一樣的事情不再是麻煩而又無(wú)聊的了。在下面的例子里,您一定會(huì)找到驚喜的。
::::::::::圓圈方陣.bat::::::::::
@echo off
setlocal EnableDelayedExpansion
set var=○
for /l %%i in (1,1,7) do set var=%var%!var!
:: 此時(shí)變量 var 已經(jīng)變成一行連續(xù)的8個(gè)圓圈了
for /l %%i in (1,1,8) do (
echo 這是第 %%i 份>輸出結(jié)果%%i.txt
for /l %%j in (1,1,8) do echo %var%>>輸出結(jié)果%%i.txt
)
echo 8 X 8 的 ○ 矩陣已經(jīng)畫好,并保存到8份文本文件里了
pause
::::::::::::::::::::::::::::::::
注意:%%i ,上一節(jié)中提到過(guò),在批處理文件中需要用連續(xù)的兩個(gè)百分號(hào) %% 來(lái)描述循環(huán)變量 i ,而不是一個(gè)。
注意:%var% 與 !var! ,它們的用法與區(qū)別,在第4.1.5節(jié)中有解釋。
注意:i 與 j ,在循環(huán)里面再套循環(huán)時(shí),前一個(gè)循環(huán)變量 i 在沒(méi)有釋放之前,不應(yīng)該讓第二個(gè)循環(huán)變量的名稱與 i 重復(fù)。
注意:> 與 >> ,同樣是向某設(shè)備里輸出,但卻有區(qū)別,請(qǐng)參閱第2.2節(jié)。
4.2.4 for 也可以對(duì)指定范圍內(nèi)的文字進(jìn)行循。for 后面跟參數(shù) /f ,/f 后面跟選項(xiàng),所指定的范圍 in 里可以是一個(gè)文件里的文字,可以是一個(gè)字符串,也可以是一條命令的輸出結(jié)果。我們首先以一個(gè)文件里的文字作為循環(huán)對(duì)象,循環(huán)時(shí),每一行將被循環(huán)一次。
::::::::::文字篩選.txt::::::::::
@echo off
echo 測(cè)試 文字篩選.txt 里每一行的首單詞
for /f %%i in (文字篩選.txt) do echo %%i
pause
echo.
echo skip=2 表示前兩行被跳過(guò)
for /f "skip=2" %%i in (文字篩選.txt) do echo %%i
pause
echo.
echo tokens=2,4-6 表示提取每行的第2個(gè)、以及第4到6個(gè)單詞
for /f "skip=2 tokens=2,4-6" %%i in (文字篩選.txt) do echo %%i, %%j, %%k, %%l.
pause
echo.
echo eol=N 表示當(dāng)此行的首字母為 N 時(shí),就忽略該行
for /f "eol=N skip=2 tokens=2,4-6" %%i in (文字篩選.txt) do echo %%i, %%j, %%k, %%l.
pause
echo.
echo delims=e 表示不再以空格區(qū)分每個(gè)詞,而是以字母 e 作為間隔
for /f "eol=N skip=2 tokens=2,4-6 delims=e" %%i in (文字篩選.txt) do echo %%i, %%j, %%k, %%l.
pause
echo.
echo usebackq 表示雙引號(hào)里的東西是文件名而不是字符串
for /f "usebackq eol=N skip=2 tokens=2,4-6 delims=e" %%i in ("文字篩選.txt") do echo %%i, %%j, %%k, %%l.
pause
::::::::::::::::::::::::::::::::
作為測(cè)試,可以在上述批處理文件的同一路徑下創(chuàng)建一個(gè)用于測(cè)試的文本文件 文字篩選.txt ,其內(nèi)容為:
Hello there!
This text is an example of test for the batch file 文字篩選.bat.
Notice the first letter in this line, N.
If the eol charactor was set to be letter N.
The third line will not be considered by the batch.
4.2.5 ESCAPE字符 % ,通常被譯為轉(zhuǎn)義字符,但也有更形象的譯名脫逸字符、逃逸字符等。也就是說(shuō) % 不僅僅將與其相關(guān)的特定字符串轉(zhuǎn)義并替換為特定字符串,而且自身也會(huì)被“脫逸”。而且類似于C語(yǔ)言中的轉(zhuǎn)義字符 \ ,雙%會(huì)轉(zhuǎn)義并脫逸為單百分號(hào) % ,四%則脫為雙百分號(hào) %% 。[3]
注意下面這個(gè)批處理中的雙百分號(hào) %% 的用法
::::::::::::::::::::::::::::::::
@echo off
set Text=Hello world!
for /l %%i IN (0,1,11) do call echo %%Text:~%%i,1%%
pause
::::::::::::::::::::::::::::::::
參考:
目錄:
批處理的學(xué)習(xí)之一[前言]
批處理的學(xué)習(xí)之二[顯示篇]
批處理的學(xué)習(xí)之三[賦值 調(diào)用 參數(shù)]
批處理的學(xué)習(xí)之四[條件 循環(huán)]
批處理的學(xué)習(xí)之五[組合命令 管道命令]
批處理的學(xué)習(xí)之六[常用實(shí)例 上]
批處理的學(xué)習(xí)之七[常用實(shí)例 下]
批處理的學(xué)習(xí)之八[番外篇]
上次編輯 2008-12-04
聯(lián)系客服