2008年4月21日 星期一

BAT批次檔案語法(上)

加入書籤: HemiDemi MyShare Baidu Google Bookmarks Yahoo! My Web Del.icio.us Digg technorati furl

副檔名是bat(在nt/2000/xp/2003下也可以是cmd)的檔就是批次檔案。

==== 注 =======================================
.bat是dos下的批次檔案
.cmd是nt內核命令行環境的另一種批次檔案
從更廣義的角度來看,unix的shell腳本以及其他作業系統甚至應用程式中由外殼進行解釋執行的文本,都具有與批次檔案十分相似的作用,而且同樣是由專用解釋器以行為單位解釋執行,這種文本形式更通用的稱謂是腳本語言。所以從某個程度分析,batch, unix shell, awk, basic, perl 等腳本語言都是一樣的,只不過應用的範圍和解釋的平臺各有不同而已。甚至有些應用程式仍然沿用批次處理這一稱呼,而其內容和副檔名與dos的批次處理卻又完全不同。
===================================

首先批次檔案是一個文字檔案,這個檔的每一行都是一條DOS命令(大部分時候就好象我們在DOS提示符下執行的命令行一樣),你可以使用DOS下的Edit或者Windows的記事本(notepad)等任何文字檔案編輯工具創建和修改批次檔案。

==== 注 ===================
批次檔案中完全可以使用非dos命令,甚至可以使用不具有可執行特性的普通資料性檔,這緣於windows系統這個新型解釋平臺的涉入,使得批次處理的應用越來越"邊緣化"。所以我們討論的批次處理應該限定在dos環境或者命令行環境中,否則很多觀念和設定都需要做比較大的變動。
========================

其次,批次檔案是一種簡單的程式,可以通過條件語句(if)和流程控制語句(goto)來控制命令執行的流程,在批次處理中也可以使用迴圈語句(for)來迴圈執行一條命令。當然,批次檔案的編程能力與C語言等編程語句比起來是十分有限的,也是十分不規範的。批次處理的程式語句就是一條條的DOS命令(包括內部命令和外部命令),而批次處理的能力主要取決於你所使用的命令。

==== 注 ==================
批次檔案(batch file)也可以稱之為批次處理程式(batch program),這一點與編譯型語言有所不同,就c語言來說,副檔名為c或者cpp的檔可以稱之為c語言檔或者c語言源代碼,但只有編譯連接後的exe檔才可以稱之為c語言程式。因為批次檔案本身既具有文本的可讀性,又具有程式的可執行性,這些稱謂的界限是比較模糊的。
===========================

第三,每個編寫好的批次檔案都相當於一個DOS的外部命令,你可以把它所在的目錄放到你的DOS搜索路徑(path)中來使得它可以在任意位置執行。一個良好的習慣是在硬碟上建立一個bat或者batch目錄(例如C:\BATCH),然後將所有你編寫的批次檔案放到該目錄中,這樣只要在path中設定上c:\batch,你就可以在任意位置執行所有你編寫的批次處理程式。

==== 注 =====
純以dos系統而言,可執行程式大約可以細分為五類,依照執行優先順序由高到低排列分別是:DOSKEY巨集命令(預先駐留記憶體),COMMAND.COM中的內部命令(根據記憶體的環境隨時進駐記憶體),以com為副檔名的可執行程式(由command.com 直接載入記憶體),以exe位元副檔名的可執行程式(由command.com 重定位後載入記憶體),以bat位元副檔名的批次處理程式(由command.com 解釋分析,根據其內容按優先順序順序調用第2,3,4,5種可執行程式,分析一行,執行一行,檔本身不載入記憶體)
============

第四,在DOS和Win9x/Me系統下,C:盤根目錄下的AUTOEXEC.BAT批次檔案是自動執行批次檔案,每次系統啟動時會自動執行該檔,你可以將系統每次啟動時都要執行的命令放入該檔中,例如設定搜索路徑,調入滑鼠驅動和磁片緩存,設定系統環境變數等。下麵是一個執行於Windows 98下的autoexec.bat的示例:
@ECHO OFF
PATH C:\WINDOWS;C:\WINDOWS\COMMAND;C:\UCDOS;C:\DOSTools;

C:\SYSTOOLS;C:\WINTOOLS;C:\BATCH
LH SMARTDRV.EXE /X
LH DOSKEY.COM /insert
LH CTMOUSE.EXE
SET TEMP=D:\TEMP
SET TMP=D:\TEMP
==== 注 =====
AUTOEXEC.BAT為DOS系統的自動執行批次檔案,由COMMAND.COM啟動時解釋執行;
而在Win9x環境中,不僅增加支持了 DOSSTART.BAT, WINSTART.BAT 等許多其他自動執行的批次檔案,對AUTOEXEC.BAT 也增加了 .DOS .W40 .BAK .OLD .PWS 等許多變體以適應複雜的環境和多變的需求。
==== willsort 編注 =============
以下關於命令的分類,有很多值得推敲的地方。常用命令中的@本不是命令,而dir、copy等也很常用的命令卻沒有列入, 而特殊命令中所有命令對我來說都是常用命令。建議將批次處理所引用的命令分為內部命令、外部命令、第三方程式三類。而內部命令和外部命令中別有一類是專用於或常用於批次處理中的命令可稱之為"批次處理命令"。

以下摘錄MS-DOS 6.22 幫助文檔中關於"批次處理命令"的文字,當然,其中有些概念和定義已經有些落後了。

批次處理命令

批次檔案或批次處理程式是一個包含若干MS-DOS命令的正文檔,副檔名為.BAT。當在命令提示符下敲入批次處理程式的名稱時,MS-DOS成組執行此批次處理程式中的命令。

任何在命令提示符下可使用的命令都可用在批次處理程式中。此外,下面MS-DOS命令是專門在批次處理程式中使用的。
==========

常用命令

echo、@、call、pause、rem(小技巧:用::代替rem)是批次檔案最常用的幾個命令,我們就從他們開始學起。

==== 注 ===========
首先, @ 不是一個命令, 而是DOS 批次處理的一個特殊標記符, 僅用於遮罩命令行回顯. 下面是DOS命令行或批次處理中可能會見到的一些特殊標記符:
CR(0D) 命令行結束符
Escape(1B) ANSI轉義字元引導符
Space(20) 常用的參數界定符
Tab(09) ; = 不常用的參數界定符
+ COPY命令文件連接符
* ? 文件通配符
"" 字串界定符
| 命令管道符
< > >> 文件重定向符
@ 命令行回顯遮罩符
/ 參數開關引導符
: 批次處理標籤引導符
% 批次處理變數引導符

其次, :: 確實可以起到rem 的注釋作用, 而且更簡潔有效; 但有兩點需要注意:
第一, 除了 :: 之外, 任何以 :開頭的字元行, 在批次處理中都被視作標號, 而直接忽略其後的所有內容, 只是為了與正常的標號相區別, 建議使用 goto 所無法識別的標號, 即在 :後緊跟一個非字母數位元的一個特殊符號.
第二, 與rem 不同的是, ::後的字元行在執行時不會回顯, 無論是否用echo on打開命令行回顯狀態, 因為命令解釋器不認為他是一個有效的命令行, 就此點來看, rem 在某些場合下將比 :: 更為適用; 另外, rem 可以用於 config.sys 文件中.
=====================

echo 表示顯示此命令後的字元
echo off 表示在此語句後所有執行的命令都不顯示命令行本身
@與echo off相象,但它是加在每個命令行的最前面,表示執行時不顯示這一行的命令行(只能影響當前行)。
call 調用另一個批次檔案(如果不用call而直接調用別的批次檔案,那麼執行完那個批次檔案後將無法返回當前檔並執行當前檔的後續命令)。
pause 執行此句會暫停批次處理的執行並在螢幕上顯示Press any key to continue...的提示,等待用戶按任意鍵後繼續
rem 表示此命令後的字元為解釋行(注釋),不執行,只是給自己今後參考用的(相當於程式中的注釋)。
==== 注 =====
此處的描述較為混亂, 不如直接引用個命令的命令行幫助更為條理

-------------------------
ECHO

當程式執行時,顯示或隱藏批次處理程式中的正文。也可用於允許或禁止命令的回顯。

在執行批次處理程式時,MS-DOS一般在螢幕上顯示(回顯)批次處理程式中的命令。
使用ECHO命令可關閉此功能。

語法

ECHO [ON|OFF]

若要用echo命令顯示一條命令,可用下述語法:

echo [message]

參數

ON|OFF
指定是否允許命令的回顯。若要顯示當前的ECHO的設定,可使用不帶參數的ECHO
命令。

message
指定讓MS-DOS在螢幕上顯示的正文。

-------------------

CALL

從一個批次處理程式中調用另一個批次處理程式,而不會引起第一個批次處理的中止。

語法

CALL [drive:][path]filename [batch-parameters]

參數

[drive:][path]filename
指定要調用的批次處理程式的名字及其存放處。檔案名必須用.BAT作副檔名。

batch-parameters
指定批次處理程式所需的命令行資訊。

-------------------------------

PAUSE

暫停批次處理程式的執行並顯示一條消息,提示用戶按任意鍵繼續執行。只能在批處
理程式中使用該命令。

語法

PAUSE

REM

在批次檔案或CONFIG.SYS中加入注解。也可用REM命令來遮罩命令(在CONFIG.SYS
中也可以用分號 ; 代替REM命令,但在批次檔案中則不能替代)。

語法

REM [string]

參數

string
指定要遮罩的命令或要包含的注解。
=======================

例1:用edit編輯a.bat檔,輸入下列內容後存檔為c:\a.bat,執行該批次檔案後可實現:將根目錄中所有檔寫入 a.txt中,啟動UCDOS,進入WPS等功能。

批次檔案的內容為: 命令注釋:

@echo off 不顯示後續命令行及當前命令行
dir c:\*.* >a.txt 將c盤文件列表寫入a.txt
call c:\ucdos\ucdos.bat 調用ucdos
echo 你好 顯示"你好"
pause 暫停,等待按鍵繼續
rem 準備執行wps 注釋:準備執行wps
cd ucdos 進入ucdos目錄
wps 執行wps

批次檔案的參數

批次檔案還可以像C語言的函數一樣使用參數(相當於DOS命令的命令行參數),這需要用到一個參數表示符"%"。

%[1-9]表示參數,參數是指在執行批次檔案時在檔案名後加的以空格(或者Tab)分隔的字串。變數可以從%0到%9,%0表示批次處理命令本身,其他參數字串用%1到%9順序表示。

例2:C:根目錄下有一批次檔案名為f.bat,內容為:
@echo off
format %1

如果執行C:\>f a:
那麼在執行f.bat時,%1就表示a:,這樣format %1就相當於format a:,於是上面的命令執行時實際執行的是format a:

例3:C:根目錄下一批次檔案名為t.bat,內容為:
@echo off
type %1
type %2

那麼執行C:\>t a.txt b.txt
%1 : 表示a.txt
%2 : 表示b.txt
於是上面的命令將順序地顯示a.txt和b.txt檔的內容。

==== 注 ===============
參數在批次處理中也作為變數處理, 所以同樣使用百分號作為引導符, 其後跟0-9中的一個數字構成參數引用符. 引用符和參數之間 (例如上文中的 %1 與 a: ) 的關係類似於變數指標與變數值的關係. 當我們要引用第十一個或更多個參數時, 就必須移動DOS 的參數起始指標. shift 命令正充當了這個移動指標的角色, 它將參數的起始指標移動到下一個參數, 類似C 語言中的指標操作. 圖示如下:

初始狀態, cmd 為命令名, 可以用 %0 引用
cmd arg1 arg2 arg3 arg4 arg5 arg6 arg7 arg8 arg9 arg10
^ ^ ^ ^ ^ ^ ^ ^ ^ ^
| | | | | | | | | |
%0 %1 %2 %3 %4 %5 %6 %7 %8 %9

經過1次shift後, cmd 將無法被引用
cmd arg1 arg2 arg3 arg4 arg5 arg6 arg7 arg8 arg9 arg10
^ ^ ^ ^ ^ ^ ^ ^ ^ ^
| | | | | | | | | |
%0 %1 %2 %3 %4 %5 %6 %7 %8 %9

經過2次shift後, arg1也被廢棄, %9指向為空, 沒有引用意義
cmd arg1 arg2 arg3 arg4 arg5 arg6 arg7 arg8 arg9 arg10
^ ^ ^ ^ ^ ^ ^ ^ ^
| | | | | | | | |
%0 %1 %2 %3 %4 %5 %6 %7 %8

遺憾的是, win9x 和DOS下均不支援 shift 的逆操作. 只有在 nt 內核命令行環境下, shift 才支援 /n 參數, 可以以第一參數為基準返複移動起始指標.
=================

特殊命令

if goto choice for是批次檔案中比較高級的命令,如果這幾個你用得很熟練,你就是批次檔案的專家啦。

一、if 是條件語句,用來判斷是否符合規定的條件,從而決定執行不同的命令。 有三種格式:

1、if [not] "參數" == "字串" 待執行的命令

參數如果等於(not表示不等,下同)指定的字串,則條件成立,執行命令,否則執行下一句。

例:if "%1"=="a" format a:

====

if 的命令行幫助中關於此點的描述為:
IF [NOT] string1==string2 command
在此有以下幾點需要注意:
1. 包含字串的雙引號不是語法所必須的, 而只是習慣上使用的一種"防空"字元
2. string1 未必是參數, 它也可以是環境變數, 迴圈變數以及其他字串常量或變數
3. command 不是語法所必須的, string2 後跟一個空格就可以構成一個有效的命令行
=============================

2、if [not] exist [路徑\]檔案名 待執行的命令
如果有指定的檔,則條件成立,執行命令,否則執行下一句。

如: if exist c:\config.sys type c:\config.sys
表示如果存在c:\config.sys檔,則顯示它的內容。

****** 注 ********
也可以使用以下的用法:
if exist command
device 是指DOS系統中已載入的設備, 在win98下通常有:
AUX, PRN, CON, NUL
COM1, COM2, COM3, COM4
LPT1, LPT2, LPT3, LPT4
XMSXXXX0, EMMXXXX0
A: B: C: ...,
CLOCK$, CONFIG$, DblBuff$, IFS$HLP$
具體的內容會因硬軟體環境的不同而略有差異, 使用這些設備名稱時, 需要保證以下三點:
1. 該設備確實存在(由軟體虛擬的設備除外)
2. 該設備驅動程式已載入(aux, prn等標準設備由系統缺省定義)
3. 該設備已準備好(主要是指a: b: ..., com1..., lpt1...等)
可通過命令 mem/d | find "device" /i 來檢閱你的系統中所載入的設備
另外, 在DOS系統中, 設備也被認為是一種特殊的檔, 而檔也可以稱作字元設備; 因為設備(device)與檔都是使用控制碼(handle)來管理的, 控制碼就是名字, 類似於檔案名, 只不過控制碼不是應用於磁片管理, 而是應用於記憶體管理而已, 所謂設備載入也即指在記憶體中為其分配可引用的控制碼.
==================================

3、if errorlevel <數位> 待執行的命令

很多DOS程式在執行結束後會返回一個數位值用來表示程式執行的結果(或者狀態),通過if errorlevel命令可以判斷程式的返回值,根據不同的返回值來決定執行不同的命令(返回值必須按照從大到小的順序排列)。如果返回值等於指定的數字,則條件成立,執行命令,否則執行下一句。

如if errorlevel 2 goto x2

==== 注 ===========
返回值從大到小的順序排列不是必須的, 而只是執行命令為 goto 時的習慣用法, 當使用 set 作為執行命令時, 通常會從小到大順序排列, 比如需將返回碼置入環境變數, 就需使用以下的順序形式:

if errorlevel 1 set el=1
if errorlevel 2 set el=2
if errorlevel 3 set el=3
if errorlevel 4 set el=4
if errorlevel 5 set el=5
...

當然, 也可以使用以下迴圈來替代, 原理是一致的:
for %%e in (1 2 3 4 5 6 7 8...) do if errorlevel %%e set el=%%e

更高效簡潔的用法, 可以參考我寫的另一篇關於獲取 errorlevel 的文章

出現此種現象的原因是, if errorlevel 比較返回碼的判斷條件並非等於, 而是大於等於. 由於 goto 的跳轉特性, 由小到大排序會導致在較小的返回碼處就跳出; 而由於 set命令的 "重複" 賦值特性, 由大到小排序會導致較小的返回碼 "覆蓋" 較大的返回碼.

另外, 雖然 if errorlevel=<數字> command 也是有效的命令行, 但也只是 command.com 解釋命令行時將 = 作為命令行切分符而忽略掉罷了
===========================

二、goto 批次檔案執行到這裏將跳到goto所指定的標號(標號即label,標號用:後跟標準字串來定義)處,goto語句一般與if配合使用,根據不同的條件來執行不同的命令組。

如:

goto end

:end
echo this is the end

標號用":字串"來定義,標號所在行不被執行。

==== willsort 編注

label 常被譯為 "標籤" , 但是這並不具有廣泛的約定性.

goto 與 : 聯用可實現執行中途的跳轉, 再結合 if 可實現執行過程的條件分支, 多個 if 即可實現命令的分組, 類似 C 中 switch case 結構或者 Basic 中的 select case 結構, 大規模且結構化的命令分組即可實現高階語言中的函數功能. 以下是批次處理和C/Basic在語法結構上的對照:

Batch C / Basic
goto&: goto&:
goto&:&if if{}&else{} / if&elseif&endif
goto&:&if... switch&case / select case
goto&:&if&set&envar... function() / function(),sub()
==================================
三、choice 使用此命令可以讓用戶輸入一個字元(用於選擇),從而根據用戶的選擇返回不同的errorlevel,然後於if errorlevel配合,根據用戶的選擇執行不同的命令。

沒有留言:

狀態廣告

EasyReadMore