HOWTO · Batch

バッチスクリプトで関数を作成する

このチュートリアルでは、バッチスクリプトで関数を作成する方法について説明します。

このページの内容

Batchファイルには、専用の宣言キーワードで関数を定義する仕組みはありません。再利用可能なサブルーチンはラベルで定義し、CALL で呼び出します。CALL はラベル以降のコマンドを実行し、呼び出しの次のコマンドに戻ります。以下の例は Windows CMD の構文を使っているため、Windows 上で .bat または .cmd ファイルに保存して実行してください。

Batch関数の仕組み

Batchの「関数」は、一般にサブルーチンと呼ばれます。ラベルが処理の開始位置を示し、CALL :label がそこへ制御を移して、呼び出し元に戻る位置を保持します。ラベルだけでは独立したスコープは作られず、自動的に戻ることもありません。サブルーチン内で EXIT /B を使うと呼び出し元へ戻ります。明示的に戻らない場合、後続のラベルやコマンドへ処理が続くことがあります。サブルーチンとして呼び出されていないとき、EXIT /B は現在のバッチスクリプトを終了します。

Batch関数を定義して呼び出す

呼び出し元の処理をラベルより前に置き、メイン処理の末尾に GOTO :EOF を記述して、サブルーチンへそのまま処理が流れ込まないようにします。生成されるスクリプトでは、サブルーチンがあいさつを表示して呼び出し元へ戻ります。

CMDがここで実行されたかのように誤解させずに、小さな Windows 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 が2番目の引数というように参照できます。最初の引数から前後の引用符を取り除いて使う場合は、%~1 を使います。チルダを付けても、値をどのコマンドにも安全に挿入できるわけではありません。パスや文字列として使う値は引用符で囲んでください。

次の Python の例は、スペースを含む引数を1つ渡す完全な 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 の例は、2つの引数を受け取るサブルーチンを呼び出し、CALL の直後にステータスを確認して、成功時に結果の変数を読み取る完全な Batch スクリプトを出力します。出力されたソースを .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 はローカルになります。同じコマンド行では、ENDLOCAL が実行される前に CMD が %_sum% を展開し、その値を呼び出し元の 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

最初の呼び出しでは必須の値がないため失敗側の分岐に進み、2回目は成功側の分岐に進みます。if errorlevel 1 は、現在のエラーレベルが1以上であることを意味します。特定のコードを判定する必要がある場合は、大きいコードから降順に確認してください。有効な引数を受け取った場合は、サブルーチンの処理を続け、最後に EXIT /B 0 を実行できます。

サブルーチンから戻るときは EXIT ではなく EXIT /B を使ってください。EXIT は CMD セッションを閉じますが、EXIT /B は現在のバッチ実行コンテキストから戻ります。CALL の呼び出し先ラベルが存在しない場合、CMDはエラーを報告します。ラベルの表記を統一し、サブルーチンの呼び出しとラベルの対応を明確にしておくと、原因を特定しやすくなります。Pythonの例はBatchソースを出力するだけで、実行はしません。Batchの動作を確認するには、保存したスクリプトをWindows CMDで実行してください。