2009年2月4日 星期三

FOR語句的應用

可能很多人不知道在Batch裡也有迴圈可以運用喔,我個人覺得這功能非常強大,雖然我只會簡單的,但有時可幫助我節省不少工作時間呢!
  可在命令列下"for /?"得到詳細資訊喔

0.基本應用(沒有啟用擴充命令)
 就是手動去指定迴圈範圍,語句如下
 FOR %variable IN (set) DO 指令 [command-parameters]

 例子1:如何快速找出硬碟CDE槽的剩餘可用空間 。
 語句1: 請把&替換成shift+\囉(blogger把我字給吃了)
for %i in (c d e) do @dir %i: & find "位元組可用"
 22 個目錄 6,034,595,840 位元組可用
 15 個目錄 1,634,000,896 位元組可用
 8 個目錄 3,506,417,664 位元組可用
 補充1:@ 只是讓輸出結果不包括 dir命令本身而已

 例子2:參考刪除隨身碟病毒裡的一段,內容意思是解除所有硬碟內的autorun.inf及ntdelet.com的屬性,然後刪除它們並隱藏訊息 。
 語句2:
for %%x in (C D E F G H I J K L M N O P Q R S T U V W X Y Z) do (
attrib -r -s -h -a %%x:\autorun.inf >nul 2>nul&&attrib -r -s -h -a %%x:\ntdelect.com >nul 2>nul
del %%x:\autorun.inf /q /f >nul 2>nul&&del %%x:\ntdelect.com /q /f >nul 2>nul )
 補充2:&&的意思是前面命令成功才接著作後面的命令,各位注意可以用小括號來包更多的命令喔,如果要在批次程式中使用 FOR 指令,請指定 %%variable,而不要指定%variable

1.用/R參數列舉所有目錄
 
語句如下
 FOR /R [[drive:]path] %variable IN (set) DO command [command-parameters]

 例子3:用for來實現與dir /s /b E:\test\*.txt一樣的結果 。
 語句3:
for /R E:\test %i in (*.txt) do echo %i
 補充3:運用得當就可以對當前目錄下所有檔(包括子目錄裏面的檔)進行操作,像例子4

 例子4:用Subversion版控來管理程式碼時,若要將某各版本全部取出,往往每層目錄裡都含有".svn"的隱藏目錄,對用來上線來說,那些目錄都是多餘的,此時就可以利用for /r來清除這多餘目錄囉。

 語句4:
for /R d:\33 %i in (.) do @if exist %i\.svn rd /s /q "%i\.svn"
 補充4:如果 set 只是單一句點 (.) 字元,它只會列舉樹狀目錄結構喔。然後用if exist來判斷的原因是因為for只是機械化的列舉目錄,在此例底下不一定有.svn目錄,所以加判斷會安全點。最後因為rd /s /q這指令太可怕了,使用前最好先替代成echo看一下,要不然執行錯誤可是很慘的,像是例子3那樣。差點忘了一點,列舉目錄結構會多一層".",像"d:\33\cat\.",但這並不影響執行結果喔。

2. 用/F參數將檔案內容作為迴圈範圍
 語句如下
 
FOR /F ["options"] %variable IN (file-set) DO command [command-parameters]

 例子5:假設我有一個jj.txt檔案列表,我想連同檔案目錄的架構一起複製到c槽,檔案列表如下

c:\temp\a1.txt
c:\temp\test\a2.txt
c:\temp\test\f\a3.txt
c:\temp\bbb\a4.txt

 語句5:
for /f %%i in (C:\jj.txt) do (xcopy %%i c:%%~pi /Y)
 補充5:只要是 %~ 開頭的操作符號,都是檔案名的分離操作,具體請看 for /? 或語句7。

3.用/F參數將命令結果當作迴圈範圍
 語句如下
 
FOR /F ["options"] %variable IN ('command') DO command [command-parameters]

 例子6:把date /T輸出的"2009/02/05 星期四"拆掉然後轉換成"2009-02-05"
 語句6:
for /f "tokens=1,2,3 delims=/ " %i in ('date /T') do echo %i-%j-%k
2009-02-05
補充6:此例用到"options"的額外參數,"delims=xxx"指分隔符號的集合,此例分隔符號是"/"與" ",意思是把"2009/02/05 星期四"依分隔符號拆成"2009","02","05"等。"tokens=x,y,m-n"是變數指定的意思,此例是把拆出來的第一個變數指定給%i,第二個給%j,依此類推囉

4. 使用%~來加強完整檔案路徑的分離功能

 直接看語句與結果比較快啦
 語句7:
for /f "delims=" %%i in ("C:\WINNT\system32\drivers\etc\lmhosts.sam") do (
echo.
echo 一個完全符合的路徑名稱 %%~fi
echo 磁碟機字元 %%~di
echo 路徑 %%~pi
echo 檔名 %%~ni
echo 副檔名 %%~xi
echo 路徑只包含短檔名%%~si
echo 檔案屬性 %%~ai
echo 檔案的日期時間 %%~ti
echo 磁碟機字元與路 %%~dpi
echo 檔名與副檔名 %%~nxi
echo 含短檔名的完全路徑 %%~fsi)


一個完全符合的路徑名稱 C:\WINNT\system32\drivers\etc\lmhosts.sam
磁碟機字元 C:
路徑 \WINNT\system32\drivers\etc\
檔名 lmhosts
副檔名 .sam
路徑只包含短檔名C:\WINNT\system32\drivers\etc\lmhosts.sam
檔案屬性 --a------
檔案的日期時間 03/06/26 08:00p
磁碟機字元與路 C:\WINNT\system32\drivers\etc\
檔名與副檔名 lmhosts.sam
含短檔名的完全路徑 C:\WINNT\system32\drivers\etc\lmhosts.sam


5. 用/L參數來指定起始值終值的迴圈範圍
 這個跟一般程式很像囉,語句如下
 FOR /L %variable IN (start,step,end) DO command [command-parameters]

 例子8:假設我想ping一段ip範圍,如11.111.2.115~11.111.2.130,如有回應就印出該ip ok之類的
 語句8: 請把一個的"&"替換成shift+\囉,連續兩個的不用替換(blogger把我字給吃了)
for /L %%i in (115,1,130) do ping -n 1 11.111.2.%%i & find "reply" /i && echo 11.111.2.%%i ok

6 則留言:

  1. 關於例子2,隨身碟病毒那段。假設 attrib 用A表示、del 用B表示
    那麼執行的表示式 應該是這樣 A&&A B&&B。請問等同於這樣嗎?
    A A B B 或 A&&A&&B&&B
    && 前面有提到,是接著執行,不過,我看上面這些句子,看起來像是獨立的句子,所以應該可以個別執行? 如果不行,那麼應該全部都要加上&&,為什麼A和B之間,會有個空格? 還請版主解惑,大大的文章蠻精闢的,對於學習很有幫助,感謝大大的文章。

    回覆刪除
    回覆
    1. &&通常是用在有邏輯先後次序時用的,有點像if,某個條件成立,才去做後面的,不用的話變成前後兩個命令都會執行,如果前面條件不成立,後面的動作一樣照做就會出錯,batch命令出錯就返回,就不會往下做了,這種情況要避開錯誤就會用&&。此例要del檔案前,如果檔案是唯獨的,就不能del,所以必須先用attrib解除唯獨狀態,再del檔案,如果檔案本身就是可讀寫的,是不一定要執行attrib的,所以attrib與del是分開的兩段命令,中間不算空格,應該是段落結束符號Enter啦,你說的沒錯,當然可以分開個別執行啊,問題在於batch命令要完整執行,中間是不能出錯的,不知這樣懂我意思嗎?

      刪除
  2. for /f %%i in (C:\jj.txt) do (xcopy %%i c:%%~pi /Y)
    請問要複製到C盤,為什麼要加上%%PI ?
    這樣不是會連同%i本身一起擴充?
    如果照著上面那樣,會出現 "檔案不能複製到其本身之上"

    回覆刪除
    回覆
    1. 喔...可能jj.txt裡面的sample不恰當,應該用非C槽的才對,然後因為我要複製目錄結構,所以用%~pi取目錄名稱

      刪除
  3. 請問 %%~si 和 %%~fsi 有甚麼差別 ?
    跑出來的結果一模一樣。 謝謝你

    回覆刪除
    回覆
    1. 這我也不知道耶,可能某些狀況下有差吧...@@

      刪除