HOWTO · Batch
在批處理指令碼中建立函式
本教程將討論如何在批處理指令碼中建立函式。
本頁內容
Batch 檔案沒有用獨立的宣告關鍵字來定義函式。可重複使用的子程序是以標籤表示,並透過 CALL 呼叫;CALL 會執行該標籤後方的命令,然後返回呼叫之後的下一個命令。以下範例使用 Windows CMD 語法,請在 Windows 上將其存成 .bat 或 .cmd 檔案後執行。
Batch 函式的運作方式
Batch 中的「函式」通常稱為子程序。它的標籤名稱代表進入點,而 CALL :label 會將控制流程轉移到該處,並保留返回位置。標籤本身不會建立獨立作用域,也不會自動返回。請在子程序中使用 EXIT /B 返回呼叫端;若沒有明確返回,執行流程可能會繼續進入後續標籤和命令。如果目前的批次指令碼不是以子程序方式呼叫,EXIT /B 會結束目前的批次指令碼。
定義並呼叫 Batch 函式
請將呼叫指令放在標籤之前,並以 GOTO :EOF 結束主程式區段,避免執行流程直接落入子程序。在產生的指令碼中,子程序會輸出問候訊息,然後返回呼叫端。
若要查看一個簡短的 Windows CMD 指令碼,且不表示 CMD 已在此處執行,請執行這段 Python 程式。它會輸出 Batch 原始碼;請將輸出存成 .bat 或 .cmd 檔案,再於 Windows CMD 中執行。
本節中的程式碼以及顯示的標籤或輸出仍為英文。
print('''@echo off
call :greet "Ada"
echo Back in the main script.
goto :eof
:greet
echo Hello, %~1!
exit /b 0''')
@echo off
call :greet "Ada"
echo Back in the main script.
goto :eof
:greet
echo Hello, %~1!
exit /b 0
本例中的程式碼及其顯示的標籤或輸出仍為英文。產生的指令碼適用於 Windows CMD;Python 只會輸出原始碼,不會執行它。GOTO :EOF 會結束主流程,而 EXIT /B 0 會讓被呼叫的標籤以成功狀態返回。0 是慣用的成功代碼;非零代碼則可向呼叫端表示失敗。
傳遞引數給 Batch 函式
引數以空格分隔,接在 CALL 命令中的標籤後方。在子程序內,%1 代表第一個引數,%2 代表第二個引數,依此類推。若要取得已移除外層引號的第一個引數,建議使用 %~1;波浪號不會讓值自動適用於所有命令,因此將值用作路徑或文字時仍應加上引號。
這個 Python 範例會輸出一份完整的 Batch 指令碼,並傳遞一個含空格的引數;請將輸出的原始碼存成 .bat 或 .cmd 檔案,再於 Windows CMD 中執行。:show 子程序會以 %~1 讀取該值。
本節中的程式碼以及顯示的標籤或輸出仍為英文。
print("""@echo off
call :show "Ada Lovelace"
goto :eof
:show
echo Name: %~1
exit /b 0""")
@echo off
call :show "Ada Lovelace"
goto :eof
:show
echo Name: %~1
exit /b 0
本例中的程式碼及其顯示的標籤或輸出仍為英文。當值可能含有空格或命令中繼字元時,請在加上引號的比較式或 SET 指派中展開引數。Batch 會經過多個剖析與展開階段,因此 %、& 和 | 等複雜值需要特別小心。
傳回值與結束代碼
Batch 沒有內建的函式傳回值欄位。常見做法是將結果放入環境變數,並另外使用子程序的結束代碼表示成功或失敗。這個 Python 範例會輸出一份完整的 Batch 指令碼:呼叫一個有兩個引數的子程序、在 CALL 後立即檢查狀態,並在成功時讀取結果變數。請將輸出的原始碼存成 .bat 或 .cmd 檔案,再於 Windows CMD 中執行。
本節中的程式碼以及顯示的標籤或輸出仍為英文。
print("""@echo off
setlocal EnableExtensions
call :add 5 10
if errorlevel 1 goto add_failed
echo Sum: %sum%
goto :eof
:add_failed
echo Addition failed.
goto :eof
:add
if "%~1"=="" exit /b 1
if "%~2"=="" exit /b 1
setlocal
set /a "_sum=%~1 + %~2"
endlocal & set "sum=%_sum%"
exit /b 0""")
@echo off
setlocal EnableExtensions
call :add 5 10
if errorlevel 1 goto add_failed
echo Sum: %sum%
goto :eof
:add_failed
echo Addition failed.
goto :eof
:add
if "%~1"=="" exit /b 1
if "%~2"=="" exit /b 1
setlocal
set /a "_sum=%~1 + %~2"
endlocal & set "sum=%_sum%"
exit /b 0
本例中的程式碼及其顯示的標籤或輸出仍為英文。標籤會將位置引數讀作 %~1 和 %~2。SETLOCAL 會讓暫存變數 _sum 保持在區域範圍內;在同一命令列上,CMD 會先展開 %_sum%,再執行 ENDLOCAL,接著將該值指派給呼叫端的 sum 變數。請讓 ENDLOCAL & SET 保持在同一行。此範例預期引數是整數;缺少引數時會傳回狀態 1,加法完成時則會傳回狀態 0。
處理 Batch 函式中的錯誤
請在子程序開頭附近驗證必要輸入;若輸入缺漏,就傳回非零狀態。這個 Python 範例會輸出一份完整的 Batch 指令碼,使用缺少及具備輸入的情況呼叫同一個驗證標籤;每個 if errorlevel 1 檢查都會緊接在 CALL 之後。請將輸出的原始碼存成 .bat 或 .cmd 檔案,再於 Windows CMD 中執行。
本節中的程式碼以及顯示的標籤或輸出仍為英文。
print("""@echo off
call :require_value
if errorlevel 1 (
echo Missing input: rejected with status 1.
) else (
echo Missing input: accepted.
)
call :require_value "report.txt"
if errorlevel 1 (
echo Valid input: rejected.
) else (
echo Valid input: accepted with status 0.
)
goto :eof
:require_value
if "%~1"=="" exit /b 1
exit /b 0""")
@echo off
call :require_value
if errorlevel 1 (
echo Missing input: rejected with status 1.
) else (
echo Missing input: accepted.
)
call :require_value "report.txt"
if errorlevel 1 (
echo Valid input: rejected.
) else (
echo Valid input: accepted with status 0.
)
goto :eof
:require_value
if "%~1"=="" exit /b 1
exit /b 0
本例中的程式碼及其顯示的標籤或輸出仍為英文。第一次呼叫因缺少必要值而進入失敗分支;第二次則進入成功分支。if errorlevel 1 表示目前的錯誤層級至少為 1;若需要判斷確切代碼,請依代碼由高至低檢查。收到有效引數後,子程序可以繼續執行工作,並以 EXIT /B 0 結束。
子程序返回時請使用 EXIT /B,不要使用 EXIT:EXIT 會關閉 CMD 工作階段,而 EXIT /B 會從目前的批次執行環境返回。若 CALL 指向不存在的標籤,CMD 會報錯;統一標籤拼法,並讓子程序呼叫與對應標籤清楚成對,有助於診斷問題。Python 範例只會輸出 Batch 原始碼,不會執行它;請在 Windows CMD 中執行存好的指令碼,才能觀察 Batch 的執行行為。