批處理指令碼——基礎語法
建立批處理指令碼
批處理指令碼的字尾名是.bat或者.cmd。在批處理指令碼——基礎中已經介紹過一個簡單的指令碼:
@echo "Hello world"
@PAUSE
並且這個指令碼已經能夠正常執行:
通常可以在執行完指令碼之後返回一個值,來表示這個函式執行狀態:
@echo "Hello world"
@exit /b 0
上述的exit命令就是來完成返回的操作的,注意這裡的/b表示退出當前的指令碼而不是退出cmd.exe應用,而之後接的0表示返回狀態,通常0表示正常返回,其它值表示異常返回,而異常返回使用的值由指令碼自己定義。
關於exit的說明如下:
以上就是一個最基礎的指令碼。
下面的內容開始介紹批處理的基本語法,不過在此之前說明下後續程式碼使用的程式設計環境。
之後的程式碼將使用Visual Code來說明,使用該工具可以一邊寫一邊執行,而不需要再開一個cmd.exe命令列:
關於Visual Code的介紹,可以參考Visual Studio Code使用心得 。
註釋
首先說明下批處理指令碼使用的註釋,它跟一般的語言不同,使用的註釋比較詭異。
主要有兩種,一種是"::",兩個冒號,另一種是指令REM。
:: 註釋方式1 :: @echo "Hello world" :: @exit /b 0 @REM 註釋方式2 @REM @echo "Hello world" @REM @exit /b 0
需要注意幾點:
1. 冒號是英文的冒號,不要搞錯寫成中文的冒號;
2. REM由於是一條命令,所以可以加@;
關於REM,再help下這條命令:
另外一點與一般註釋不同的地方是,批處理的註釋不能放在一行程式碼的末尾,不然可能產生奇怪的後果。
引數
批處理指令碼可以帶引數,執行時的形式如下:
檢視指令碼如下:
@echo Hello %1
@exit /b 0
使用%後接數字來表示引數,其中:
%0表示程式名稱,%1表示第一個引數,%2表示第二個引數,以此類推,預設支援到%9。
檢視下面的程式碼:
@echo Hello %1 %2 %3 %4 %5 %6 %7 %8 %9 @exit /b 0
下面是一個輸入結果:
看到如果引數不足9個,後面的就是空。
如果想要支援超過9個引數,或者想要引數的位置可變,就需要藉助於一個重要的命令:shift
shift命令的作用就是從指定位置開始(預設從/1開始)左移以引數,所以我們可以通過%n加上shift來遍歷引數,下面是一個例子:
:: 去掉不必要的列印
@echo off
:: 迴圈列印所有的引數
:LOOP
:: 如果引數是空就跳出迴圈
if "%1" == "" goto END
echo Hello %1
shift
goto LOOP
:END
@echo on
@exit /b 0
上述程式碼中的if、goto等控制命令之後會講到。下面是執行的結果:
變數
變數有兩種,一個是環境變數,一個是使用者自定義變數。
變數用%xx%來讀取,其中xx是變數名。
以下是一個環境變數的例子:
以下是一個使用者變數:
上述的語句也可以直接放到批處理指令碼中:
:: 環境變數
@echo %PATH%
:: 自定義變數
@set name=beni
@echo %name%
指令碼結構化
if-else語句
以下是關於if的介紹,直接通過help if就可以檢視,具體內容如下:
執行批處理程式中的條件處理。
IF [NOT] ERRORLEVEL number command
IF [NOT] string1==string2 command
IF [NOT] EXIST filename command
NOT 指定只有條件為 false 的情況下,Windows 才
應該執行該命令。
ERRORLEVEL number 如果最後執行的程式返回一個等於或大於
指定數字的退出程式碼,指定條件為 true。
string1==string2 如果指定的文字字串匹配,指定條件為 true。
EXIST filename 如果指定的檔名存在,指定條件為 true。
command 如果符合條件,指定要執行的命令。如果指定的
條件為 FALSE,命令後可跟 ELSE 命令,該命令將
在 ELSE 關鍵字之後執行該命令。
ELSE 子句必須出現在同一行上的 IF 之後。例如:
IF EXIST filename. (
del filename.
) ELSE (
echo filename. missing.
)
由於 del 命令需要用新的一行終止,因此以下子句不會有效:
IF EXIST filename. del filename. ELSE echo filename. missing
由於 ELSE 命令必須與 IF 命令的尾端在同一行上,以下子句也
不會有效:
IF EXIST filename. del filename.
ELSE echo filename. missing
如果都放在同一行上,以下子句有效:
IF EXIST filename. (del filename.) ELSE echo filename. missing
如果命令擴充套件被啟用,IF 會如下改變:
IF [/I] string1 compare-op string2 command
IF CMDEXTVERSION number command
IF DEFINED variable command
其中, compare-op 可以是:
EQU - 等於
NEQ - 不等於
LSS - 小於
LEQ - 小於或等於
GTR - 大於
GEQ - 大於或等於
而 /I 開關(如果指定)說明要進行的字串比較不分大小寫。
/I 開關可以用於 IF 的 string1==string2 的形式上。這些
比較都是通用的;原因是,如果 string1 和 string2 都是
由數字組成的,字串會被轉換成數字,進行數字比較。
CMDEXTVERSION 條件的作用跟 ERRORLEVEL 的一樣,除了它
是在跟與命令擴充套件有關聯的內部版本號比較。第一個版本
是 1。每次對命令擴充套件有相當大的增強時,版本號會增加一個。
命令擴充套件被停用時,CMDEXTVERSION 條件不是真的。
如果已定義環境變數,DEFINED 條件的作用跟 EXIST 的一樣,
除了它取得一個環境變數,返回的結果是 true。
如果沒有名為 ERRORLEVEL 的環境變數,%ERRORLEVEL%
會擴充為 ERROLEVEL 當前數值的字串表示式;否則,你會得到
其數值。執行程式後,以下語句說明 ERRORLEVEL 的用法:
goto answer%ERRORLEVEL%
:answer0
echo Program had return code 0
:answer1
echo Program had return code 1
你也可以使用以上的數字比較:
IF %ERRORLEVEL% LEQ 1 goto okay
如果沒有名為 CMDCMDLINE 的環境變數,%CMDCMDLINE%
將在 CMD.EXE 進行任何處理前擴充為傳遞給 CMD.EXE 的原始
命令列;否則,你會得到其數值。
如果沒有名為 CMDEXTVERSION 的環境變數,
%CMDEXTVERSION% 會擴充為 CMDEXTVERSION 當前數值的
字串符表示式;否則,你會得到其數值。
for語句
以下是關於for的介紹,直接通過help for就可以檢視,具體內容如下:
對一組檔案中的每一個檔案執行某個特定命令。
FOR %variable IN (set) DO command [command-parameters]
%variable 指定一個單一字母可替換的引數。
(set) 指定一個或一組檔案。可以使用萬用字元。
command 指定對每個檔案執行的命令。
command-parameters
為特定命令指定引數或命令列開關。
在批處理程式中使用 FOR 命令時,指定變數請使用 %%variable
而不要用 %variable。變數名稱是區分大小寫的,所以 %i 不同於 %I.
如果啟用命令擴充套件,則會支援下列 FOR 命令的其他格式:
FOR /D %variable IN (set) DO command [command-parameters]
如果集中包含萬用字元,則指定與目錄名匹配,而不與檔名匹配。
FOR /R [[drive:]path] %variable IN (set) DO command [command-parameters]
檢查以 [drive:]path 為根的目錄樹,指向每個目錄中的 FOR 語句。
如果在 /R 後沒有指定目錄規範,則使用當前目錄。如果集僅為一個單點(.)字元,
則列舉該目錄樹。
FOR /L %variable IN (start,step,end) DO command [command-parameters]
該集表示以增量形式從開始到結束的一個數字序列。因此,(1,1,5)將產生序列
1 2 3 4 5,(5,-1,1)將產生序列(5 4 3 2 1)
FOR /F ["options"] %variable IN (file-set) DO command [command-parameters]
FOR /F ["options"] %variable IN ("string") DO command [command-parameters]
FOR /F ["options"] %variable IN ('command') DO command [command-parameters]
或者,如果有 usebackq 選項:
FOR /F ["options"] %variable IN (file-set) DO command [command-parameters]
FOR /F ["options"] %variable IN ("string") DO command [command-parameters]
FOR /F ["options"] %variable IN ('command') DO command [command-parameters]
fileset 為一個或多個檔名。繼續到 fileset 中的下一個檔案之前,
每份檔案都被開啟、讀取並經過處理。處理包括讀取檔案,將其分成一行行的文字,
然後將每行解析成零或更多的符號。然後用已找到的符號字串變數值呼叫 For 迴圈。
以預設方式,/F 通過每個檔案的每一行中分開的第一個空白符號。跳過空白行。
你可通過指定可選 "options" 引數替代預設解析操作。這個帶引號的字串包括一個
或多個指定不同解析選項的關鍵字。這些關鍵字為:
eol=c - 指一個行註釋字元的結尾(就一個)
skip=n - 指在檔案開始時忽略的行數。
delims=xxx - 指分隔符集。這個替換了空格和製表符的
預設分隔符集。
tokens=x,y,m-n - 指每行的哪一個符號被傳遞到每個迭代
的 for 本身。這會導致額外變數名稱的分配。m-n
格式為一個範圍。通過 nth 符號指定 mth。如果
符號字串中的最後一個字元星號,
那麼額外的變數將在最後一個符號解析之後
分配並接受行的保留文字。
usebackq - 指定新語法已在下類情況中使用:
在作為命令執行一個後引號的字串並且一個單
引號字元為文字字串命令並允許在 file-set
中使用雙引號擴起檔名稱。
某些範例可能有助:
FOR /F "eol=; tokens=2,3* delims=, " %i in (myfile.txt) do @echo %i %j %k
會分析 myfile.txt 中的每一行,忽略以分號打頭的那些行,將
每行中的第二個和第三個符號傳遞給 for 函式體,用逗號和/或
空格分隔符號。請注意,此 for 函式體的語句引用 %i 來
獲得第二個符號,引用 %j 來獲得第三個符號,引用 %k
來獲得第三個符號後的所有剩餘符號。對於帶有空格的檔案
名,你需要用雙引號將檔名括起來。為了用這種方式來使
用雙引號,還需要使用 usebackq 選項,否則,雙引號會
被理解成是用作定義某個要分析的字串的。
%i 在 for 語句中顯式宣告,%j 和 %k 是通過
tokens= 選項隱式宣告的。可以通過 tokens= 一行
指定最多 26 個符號,只要不試圖宣告一個高於字母 "z" 或
"Z" 的變數。請記住,FOR 變數是單一字母、分大小寫和全域性的變數;
而且,不能同時使用超過 52 個。
還可以在相鄰字串上使用 FOR /F 分析邏輯,方法是,
用單引號將括號之間的 file-set 括起來。這樣,該字元
串會被當作一個檔案中的一個單一輸入行進行解析。
最後,可以用 FOR /F 命令來分析命令的輸出。方法是,將
括號之間的 file-set 變成一個反括字串。該字串會
被當作命令列,傳遞到一個子 CMD.EXE,其輸出會被捕獲到
記憶體中,並被當作檔案分析。如以下例子所示:
FOR /F "usebackq delims==" %i IN (`set`) DO @echo %i
會列舉當前環境中的環境變數名稱。
另外,FOR 變數參照的替換已被增強。你現在可以使用下列
選項語法:
%~I - 刪除任何引號("),擴充套件 %I
%~fI - 將 %I 擴充套件到一個完全合格的路徑名
%~dI - 僅將 %I 擴充套件到一個驅動器號
%~pI - 僅將 %I 擴充套件到一個路徑
%~nI - 僅將 %I 擴充套件到一個檔名
%~xI - 僅將 %I 擴充套件到一個副檔名
%~sI - 擴充套件的路徑只含有短名
%~aI - 將 %I 擴充套件到檔案的檔案屬性
%~tI - 將 %I 擴充套件到檔案的日期/時間
%~zI - 將 %I 擴充套件到檔案的大小
%~$PATH:I - 查詢列在路徑環境變數的目錄,並將 %I 擴充套件
到找到的第一個完全合格的名稱。如果環境變數名
未被定義,或者沒有找到檔案,此組合鍵會擴充套件到
空字串
可以組合修飾符來得到多重結果:
%~dpI - 僅將 %I 擴充套件到一個驅動器號和路徑
%~nxI - 僅將 %I 擴充套件到一個檔名和副檔名
%~fsI - 僅將 %I 擴充套件到一個帶有短名的完整路徑名
%~dp$PATH:I - 搜尋列在路徑環境變數的目錄,並將 %I 擴充套件
到找到的第一個驅動器號和路徑。
%~ftzaI - 將 %I 擴充套件到類似輸出線路的 DIR
在以上例子中,%I 和 PATH 可用其他有效數值代替。%~ 語法
用一個有效的 FOR 變數名終止。選取類似 %I 的大寫變數名
比較易讀,而且避免與不分大小寫的組合鍵混淆。