バッチファイルでも「同じ処理を何度も書く」のを避けるためにサブルーチン(関数)が使えます。call・goto・ラベルを組み合わせた仕組みを、動作原理から丁寧に解説します。
ラベルとgotoの基本
バッチファイルでは「:ラベル名」でジャンプ先を定義し、「goto ラベル名」でそこへ飛びます。ラベルはコロン(:)で始まる行です。
@echo off
echo 処理開始
goto :STEP2
echo ← ここは飛ばされる(実行されない)
:STEP2
echo STEP2から再開
pauseただし goto の多用はコードが読みにくくなる「スパゲッティコード」になりやすいため、単純なジャンプより後述の call でサブルーチン化するのが推奨です。
callでサブルーチンを呼び出す
call :ラベル名 でサブルーチンを呼び出し、サブルーチン内で exit /b を使うと呼び出し元に戻ります。これがバッチファイルの「関数」の仕組みです。
@echo off
rem メイン処理
call :SHOW_HEADER
echo 本文の処理
call :SHOW_FOOTER
pause
exit /b 0 ← ここでバッチ全体を終了(サブルーチンに落ちないようにする)
rem ===== サブルーチン =====
:SHOW_HEADER
echo ==============================
echo バッチファイル処理ツール
echo ==============================
exit /b 0 ← callで呼ばれたら exit /b で呼び出し元に戻る
:SHOW_FOOTER
echo ==============================
echo 処理が完了しました
echo ==============================
exit /b 0重要ポイント:メイン処理の末尾に必ず exit /b 0 を書かないと、実行がそのままサブルーチンまで流れてしまいます。これはバッチ初心者が必ずハマる落とし穴です。
引数を渡してサブルーチンを汎用化する
サブルーチンに引数を渡すことで、汎用的な「関数」を作れます。%~1・%~2 でサブルーチン内の引数を参照します(チルダ付きでクォートを取り除く)。
@echo off
rem 引数付きサブルーチンの呼び出し
call :BACKUP "C:\work" "D:\backup"
call :BACKUP "C:\docs" "D:\backup"
pause
exit /b 0
rem ===== サブルーチン:バックアップ処理 =====
rem %~1 = 第1引数(コピー元)、%~2 = 第2引数(コピー先)
:BACKUP
set SRC=%~1
set DST=%~2
echo バックアップ: %SRC% → %DST%
if not exist "%DST%" mkdir "%DST%"
robocopy "%SRC%" "%DST%" /E /XO
if %errorlevel% leq 7 (
echo 完了
) else (
echo エラー発生!
)
exit /b 0戻り値を変数で受け取る
バッチファイルには正式な「戻り値」の仕組みはありませんが、サブルーチン内でセットした変数はメインからも参照できることを利用して値を返します。
@echo off
rem サブルーチンを呼び出して結果を取得
call :GET_TIMESTAMP
echo タイムスタンプ: %TIMESTAMP%
pause
exit /b 0
rem ===== 日時文字列を作るサブルーチン =====
:GET_TIMESTAMP
set TIMESTAMP=%DATE:~0,4%%DATE:~5,2%%DATE:~8,2%_%TIME:~0,2%%TIME:~3,2%%TIME:~6,2%
set TIMESTAMP=%TIMESTAMP: =0% ← 空白を0で置換(時間が1桁のとき対策)
exit /b 0setlocalとendlocalでスコープを分ける
setlocal を使うとサブルーチン内で定義した変数がメインに影響しないよう「スコープ」を分けられます。大きなバッチでは積極的に使いましょう。
:MY_FUNC
setlocal
set TEMP_VAR=これはローカル変数
echo %TEMP_VAR%
endlocal ← ここでTEMP_VARは消える
exit /b 0まとめ
- call :ラベル名 でサブルーチンを呼び出し、exit /b 0 で呼び出し元に戻る
- メイン処理の末尾に exit /b を書かないとサブルーチンに流れ込む(よくある落とし穴)
- %~1・%~2 でサブルーチンへの引数を受け取れる(チルダでクォートを除去)
- 戻り値は変数にセットしてメインから参照する方式で実現する
- setlocal / endlocal でサブルーチン内の変数スコープを分けられる
バッチファイルを書き始めた頃、メイン処理末尾のexit /bを書き忘れてサブルーチンが二重に実行されるバグで1時間悩んだことがあります。今でも必ずサブルーチンの前にexit /bを書くようにしています。
hobbyshift管理人



コメント