q:
for指令太強了
2000/xp下的for指令太強大了,用它可以免去很多重複勞動。
曾發過for的詳細介紹:for進階套用範例 ,裡面有說明。


[原創] 史上最強之dos指令 - "FOR" - 進階套用範例
bluebear

以前常覺得DOS的指令行功能太弱,無法象UNIX一樣可以用指令行完成非常複雜的操作。實際上,當MS從WIN2K開始將指令行增強後,已經借鑒了相當 多UNIX的優點,雖然還無法做到像UNIX那麼靈活,但已可完成絕大多數的工作,比如用&&和||連接兩個(或更多)指令,由前一個的 返回值來決定下一個是否執行,等等。而在這些增強中,最明顯的,就是FOR指令。

舉個例子,用適當的參數,可用FOR指令將 date /t 的輸出 從 "Sat 07/13/2002" 變成你想要的格式,比如, "2002-07-13":

程式碼:
c:\>for /f "tokens=2,3,4 delims=/ " %a in ('date /t') do @echo %c-%a-%b
2002-07-13該例將在(3)中詳細說明。


0. 基本套用

簡單說,FOR是個循環,可以用你指定的循環範圍產生一系列指令。最簡單的例子,就是人工指定循環範圍,然後對每個值執行指定的指令。例如,想快速報告每個硬碟分區的剩餘空間:

程式碼:
for %a in (c: d: e: f do @dir %a\ | find "bytes free"將輸出:
程式碼:
8 Dir(s) 1,361,334,272 bytes free
15 Dir(s) 8,505,581,568 bytes free
12 Dir(s) 12,975,149,056 bytes free
7 Dir(s) 11,658,854,400 bytes free用它可以使一些不支持萬用字元的指令對一系列文件進行操作。在WIN9X中,TYPE指令(顯示文件內容)是不支持*.txt這種格式的 (WIN2K開始TYPE已支持通配)。遇到類似情況就可以用FOR:

程式碼:
for %a in (*.txt) do type %a這些還不是FOR最強大的功能。我認為它最強大的功能,表現在以下這些進階套用:



1. 可以用 /r 參數遍歷整個目錄樹

2. 可以用 /f 參數將文本文件內容作為循環範圍

3. 可以用 /f 參數將某一指令執行結果作為循環範圍

4. 可以用 %~ 操作符將檔案名分離成檔案名、副檔名、磁碟代號等獨立部分


現分別舉例說明如下:


1. 用 /r 遍歷目錄樹

當用 *.* 或 *.txt 等檔案名萬用字元作為 for /r 的循環範圍時,可以對當前目錄下所有文件(包括子目錄裡面的文件)進行操作。舉個例子,你想在當前目錄的所有txt文件(包括子目錄)內容中尋 找"bluebear"字樣,但由於find本身不能遍歷子目錄,所以我們用for:

程式碼:
for /r . %a in (*.txt) do @find "bluebear" %afind 前面的 @ 只是讓輸出結果不包括 find 指令本身。這是DOS很早就有的功能。和FOR無關。

當用 . 作為循環範圍時,for 只將子目錄的結構(目錄名)作為循環範圍,而不包括裡面的文件。有點像 TREE 指令,不過側重點不同。TREE 的重點是用很漂亮易讀的格式輸出,而FOR的輸出適合一些自動工作,例如,我們都知道用CVS管理的項目中,每個子目錄下都會有一個CVS目錄,有時在軟 體發行時我們想把這些CVS目錄全部去掉:

程式碼:
for /r . %a in (.) do @if exist %a\CVS rd /s /q %a\CVS先用 if exist 判斷一下,是因為 for 只是機械的對每個目錄進行列舉,如果有些目錄下面沒有CVS也會被執行到。用 if exist 判斷一下比較安全。

這種移除指令威力太大,請小心使用。最好是在真正執行以上的移除指令前,將 rd /s /q 換成 @echo 先列出要刪出的目錄,驗證無誤後再換回rd /s /q:

程式碼:
for /r . %a in (.) do @if exist %a\CVS @echo %a\CVS可能目錄中會多出一層 ".",比如 c:\proj\release\.\CVS ,但不會影響指令的執行效果。


2. 將某一文件內容或指令執行結果作為循環範圍:

假如你有一個文件 todel.txt,裡面是所有要移除的文件列表,現在你想將裡面列出的每個文件都刪掉。假設這個文件是每個檔案名占一行,像這樣:

程式碼:
c:\temp\a1.txt
c:\temp\a2.txt
c:\temp\subdir\b3.txt
c:\temp\subdir\b4.txt那麼可以用FOR來完成:

程式碼:
for /f %a in (todel.txt) do del %a這個指令還可以更強大。比如你的 todel.txt 並不是象上面例子那麼乾淨,而是由DIR直接產生,有一些沒用的訊息,比如這樣:

程式碼:
Volume in drive D is DATA
Volume Serial Number is C47C-9908

Directory of D:\tmp

09/26/2001 12:50 PM 18,426 alg0925.txt
12/02/2001 04:29 AM 795 bsample.txt
04/11/2002 04:18 AM 2,043 invitation.txt
4 File(s) 25,651 bytes
0 Dir(s) 4,060,700,672 bytes freefor 仍然可以解出其中的檔案名並進行操作:

程式碼:
for /f "skip=5 tokens=5" %a in (todel.txt) do @if exist %a DEL %a當然,上面這個指令是在進行移除,如果你只是想看看哪些文件將被操作,把DEL換成echo:

程式碼:
for /f "skip=5 tokens=5" %a in (todel.txt) do @if exist %a echo %a你將看到:
程式碼:
alg0925.txt
bsample.txt
invitation.txtskip=5表示跳過前5行(就是DIR輸出的頭部訊息),tokens=5表示將每行的第5列作為循環值放入%a,正好是 檔案名。在這裡我加了一個文件存在判斷,是因為最後一行的"free"剛好也是第5列,目前還想不出好的辦法來濾掉最後兩行,所以檢查一下可保萬無一失。


3. 可以用 /f 參數將某一指令執行結果作為循環範圍

非常有用的功能。比如,我們想知道目前的環境變數有哪些名字(我們只要名字,不要值)。可是SET指令的輸出是「名字=值」的格式,現在可以用FOR來只取得名字部分:

程式碼:
FOR /F "delims==" %i IN ('set') DO @echo %i
將看到:

程式碼:
ALLUSERSPROFILE
APPDATA
CLASSPATH
CommonProgramFiles
COMPUTERNAME
ComSpec
dircmd
HOMEDRIVE
......這裡是將set指令執行的結果拿來作為循環範圍。delims==表示用=作為分隔符,由於FOR /F預設是用每行第一個TOKEN,所以可以分離出變數名。如果是想僅列出值:

程式碼:
FOR /F "delims== tokens=2" %i IN ('set') DO @echo %itokens=2和前例相同,表示將第二列(由=作為分隔符)作為循環值。

再來個更有用的例子:

我們知道 date /t (/t表示不要詢問用戶輸入)的輸出是像這樣的:

程式碼:
Sat 07/13/2002現在我想分離出日期部分,也就是13:

程式碼:
for /f "tokens=3 delims=/ " %a in ('date /t') do @echo %a實際上把 tokens後面換成1,2,3或4,你將分別得到Sat, 07, 13和2002。注意delims=/後面還有個空格,表示/和空格都是分隔符。由於這個空格delims必須是/f選項的最後一項。

再靈活一點,像本文開頭提到的,將日期用2002-07-13的格式輸出:

程式碼:
for /f "tokens=2,3,4 delims=/ " %a in ('date /t') do @echo %c-%a-%b當tokens後跟多個值時,將分別映射到%a, %b, %c等。實際上跟你指定的變數有關,如果你指定的是 %i, 它們就會用%i, %j, %k等。

靈活套用這一點,幾乎沒有做不了的事。


4. 可以用 %~ 操作符將檔案名分離成檔案名、副檔名、磁碟代號等獨立部分

這個比較簡單,就是說將循環變數的值自動分離成只要檔案名,只要副檔名,或只要磁碟代號等等。

例:要將 c:\mp3下所有mp3的歌名列出,如果用一般的 dir /b/s 或 for /r ,將會是這樣:

程式碼:
g:\mp3\Archived\05-18-01-A\游鴻明-下沙\游鴻明-01 下沙.mp3
g:\mp3\Archived\05-18-01-A\游鴻明-下沙\游鴻明-02 21個人.mp3
......
g:\mp3\Archived\05-18-01-A\王菲-寓言\王菲-阿修羅.mp3
g:\mp3\Archived\05-18-01-A\王菲-寓言\王菲-彼岸花.mp3
g:\mp3\Archived\05-18-01-A\王菲-寓言\王菲-不愛我的我不愛.mp3
......如果我只要歌名(不要路徑和".mp3"):

程式:
游鴻明-01 下沙
游鴻明-02 21個人
......
王菲-阿修羅
王菲-彼岸花
王菲-不愛我的我不愛
......那麼可以用FOR指令:

程式:
for /r g:\mp3 %a in (*.mp3) do @echo %~na凡是 %~ 開頭的操作符,都是檔案名的分離操作。具體請看 for /? 說明 。



本文舉的例子有些可能沒有實際用處,或可用其它辦法完成。僅用於體現FOR可以不借助其它工具,僅用DOS指令組合,就可完成相當靈活的工作。

具體請看 for /? 說明


我的電腦上有一些en的聽力虛擬光碟,來源碟的格式是wav的,根本沒有必要。硬碟的空間比較緊張,就想用lame壓一下。
每個虛擬盤結構大概是這樣:wave資料夾下有子8個左右子資料夾,每個子資料夾內有一些wave文件,想把這些文件壓到指定的位置,轉成mp3,體積基本變成原來的10分之一,那麼這樣作。。。。

把lame主文件放到系統檔案夾下面,方便使用。
建個bat文件,內容如下:
for /r d:\wave %%i in (*.wav) do lame --preset mw-us -m m %%i c:\%%~pni.mp3

解釋一下:
do前面是for指令的循環,/r表示對子資料夾遞回執行,找到每個wav文件,將完整的檔案名送到變數%i,%%i的寫法是因為bat的需要。
do後面是對每個找到的文件進行壓縮,參數--preset mw-us是壓成40Kbps,基本上與源文件沒什麼區別,參數-m m表示壓成單聲道。%%~pni表示只要每個文件的路徑(不包括磁碟代號)和檔案名部分(不包括副檔名)。


A:Shell 指令碼提供的 for 指令確實很強,但用在這種小問題上就有點不值了。
這個問題用 foobar2000 來解決更方便,只需要點擊幾下滑鼠,根本不用去編寫指令碼。而且一樣可以保證輸出文件的目錄結構。

如使用 WSH 就更好了,功能強得多,但編寫指令碼也相對複雜得多
%%~pni很好
以前压缩的都是得到*.wav.mp3
對每個虛擬盤,執行這個bat就可以了,很快lame就將文件壓好。
for的功能真強。。。。


http://forum.slime.com.tw/thread133482.html
arrow
arrow
    全站熱搜

    天才R 發表在 痞客邦 留言(0) 人氣()