【bat】バッチファイルのラベル・GOTO・CALL 完全ガイド|ジャンプ・引数渡し・戻り方・FOR内制限まで解説

bat

バッチファイルの制御フローを支える3つの柱が ラベル(:LABEL)・GOTO・CALL です。「GOTO は悪い」と言われることもありますが、バッチファイルでは ループ・条件分岐・サブルーチン呼び出し のすべてにラベルと GOTO/CALL が登場します。本記事では命名規則・動作の違い・実務パターンを体系的に解説します。

この記事で学べること

  • ラベル(:LABEL)の定義ルールと命名規則
  • GOTO と CALL の決定的な違い(ジャンプ vs 戻る)
  • GOTO を使ったループ・条件分岐・エラー処理
  • CALL :ラベル で引数を渡して戻ってくる仕組み
  • :EOF・GOTO :EOF の特殊な役割
  • FOR ループ内で GOTO が使えない問題と回避策
スポンサーリンク

ラベル(:LABEL)とは

ラベルはバッチファイル内のジャンプ先・処理開始点を示すマーカーです。行の先頭にコロン : を付けると、その行がラベルとして認識されます。

:START

  echo ここがSTARTラベルの処理



:ERROR_HANDLER

  echo ここがERROR_HANDLERラベルの処理

ラベルの命名規則

ルール 詳細
先頭文字 コロン : で始める :MyLabel
使える文字 英数字・アンダースコア・ハイフン・日本語も可 :処理_A
スペース ラベル名にスペースは使えない(ラベルが切れる) NG: :My Label
大文字小文字 区別しない(:start:START は同じ) :Start = :START
スコープ バッチファイル全体でグローバル(ブロックを越える) FOR 内からでも参照可
重複定義 同名ラベルが複数あると最初のものが使われる 重複は避けること

ラベル名のベストプラクティス

ラベル名に文字数の厳密な制限はありませんが、短く・役割が明確な英数字名を付けるのが推奨です。

例: :PROC_BACKUP :ERR_HANDLER のように処理の役割が一目でわかる名前にすると、大規模バッチでも可読性が保たれます。

GOTO :ジャンプ(戻らない)

GOTO ラベル名 は指定したラベルへ一方通行でジャンプします。呼び出し元には戻りません。

@echo off



echo 処理A

GOTO SKIP

echo ここはスキップされる

:SKIP

echo 処理B

実行結果:

処理A

処理B

GOTO の主な用途

用途 パターン 説明
ループ GOTO :ループラベル 条件が偽になるまでループ先頭に戻る
条件分岐のスキップ GOTO :END else 相当処理を飛ばす
エラー処理へのジャンプ GOTO :ERROR 異常発生時にエラーハンドラへ飛ぶ
バッチ終了 GOTO :EOF ファイル末尾(終了)へジャンプ

CALL :ラベル :引数を渡して戻ってくる

CALL :ラベル名 引数1 引数2 は、指定したラベルへジャンプし、処理が終わると CALL した行の次に戻ってきます。これがサブルーチン呼び出しです。

@echo off

setlocal



echo メイン開始

CALL :Greet "山田"

echo メイン終了

GOTO :EOF



:Greet

  echo こんにちは、%~1さん!

EXIT /B

実行結果:

メイン開始

こんにちは、山田さん!

メイン終了

GOTO vs CALL の決定的な違い

比較項目 GOTO :ラベル CALL :ラベル
呼び出し元に戻る 戻らない(一方通行) 戻る(EXIT /B で)
引数(%1 %2) 使えない 使える
ERRORLEVEL 返却 不可 可(EXIT /B N)
再帰呼び出し 事実上不可能 可能
主な用途 ループ・分岐・エラー処理 関数的な再利用処理

使い分けの鉄則

「処理後に元の場所に戻る必要があるか?」で判断します。

・戻る必要あり → CALL :ラベル

・戻る必要なし(ジャンプするだけ) → GOTO ラベル

:EOF という特殊ラベル

:EOF(End Of File)はバッチファイルに定義しなくても使える組み込みラベルです。

命令 動作
GOTO :EOF バッチファイルの末尾にジャンプ → バッチ終了
EXIT /B 同上(CALL 内では呼び出し元に戻る)
@echo off

setlocal



:: メイン処理

CALL :Process

echo 完了

GOTO :EOF    ← バッチここで終了。以降のラベルは実行されない



:Process

  echo 処理中

EXIT /B

GOTO :EOF をメイン末尾に書く理由

メイン処理の後に GOTO :EOF を書かないと、サブルーチン定義部(:Process など)にそのまま流れ込んで実行されます。

メイン末尾の GOTO :EOF はサブルーチン定義部への意図しない流入を防ぐ「仕切り」です。

GOTO を使ったループパターン

バッチファイルには while 文がないため、GOTO でループを実装します。

カウンタループ

@echo off

setlocal enabledelayedexpansion



set /A COUNT=0

:LOOP

  if !COUNT! GEQ 5 GOTO :LOOP_END

  echo カウント: !COUNT!

  set /A COUNT+=1

  GOTO :LOOP

:LOOP_END

echo ループ完了

入力待ちリトライループ

@echo off

:INPUT_LOOP

  set /P INPUT=コマンドを入力(qで終了): 

  if /I "%INPUT%"=="q" GOTO :EOF

  echo 入力された値: %INPUT%

  GOTO :INPUT_LOOP

GOTO を使った条件分岐パターン

IF 文と GOTO を組み合わせると、多段条件分岐が書けます。

@echo off

setlocal



set SCORE=75



if %SCORE% GEQ 90 GOTO :GRADE_A

if %SCORE% GEQ 70 GOTO :GRADE_B

if %SCORE% GEQ 50 GOTO :GRADE_C

GOTO :GRADE_F



:GRADE_A

  echo 評価: A(優)

  GOTO :EOF

:GRADE_B

  echo 評価: B(良)

  GOTO :EOF

:GRADE_C

  echo 評価: C(可)

  GOTO :EOF

:GRADE_F

  echo 評価: F(不可)

  GOTO :EOF

各ラベルの末尾に GOTO :EOF を書く理由

:GRADE_A の処理が終わった後、GOTO :EOF がなければ :GRADE_B :GRADE_C に流れ込みます。

分岐先の各ブロックは必ず GOTO :EOFEXIT /B で終わらせてください。

CALL でサブルーチンに引数を渡す

CALL でラベルを呼ぶとき、スペース区切りで引数を渡せます。サブルーチン内では %1 %2…(または %~1)で受け取ります。

@echo off

setlocal



CALL :ShowInfo "tanaka" 28 "東京"

CALL :ShowInfo "suzuki" 35 "大阪"

GOTO :EOF



:ShowInfo

  set NAME=%~1

  set AGE=%~2

  set CITY=%~3

  echo %NAME%(%AGE%歳)/ %CITY%

EXIT /B

実行結果:

tanaka(28歳)/ 東京

suzuki(35歳)/ 大阪

引数修飾子一覧

記法 意味 例(%1 = “C:\data\file.txt”)
%1 そのまま(クォート含む) "C:\data\file.txt"
%~1 クォートを除去 C:\data\file.txt
%~n1 ファイル名のみ(拡張子なし) file
%~x1 拡張子のみ .txt
%~d1 ドライブ文字のみ C:
%~p1 パスのみ(ドライブ除く) \data\
%~f1 フルパス(絶対パス) C:\data\file.txt
%~z1 ファイルサイズ(バイト) 1024

GOTO と CALL を組み合わせたエラー処理パターン

実務バッチでは「処理失敗 → エラーハンドラへ GOTO」と「ログ出力は CALL」を組み合わせるのが定番です。

@echo off

setlocal



set LOG=batch.log



CALL :Log "INFO" "バッチ開始"



xcopy /Y "source*" "dest" >nul 2>&1

if %ERRORLEVEL% NEQ 0 (

  CALL :Log "ERROR" "xcopy失敗"

  GOTO :ERROR

)



CALL :Log "INFO" "バッチ正常終了"

EXIT /B 0



:ERROR

  echo エラーが発生しました。%LOG% を確認してください。

  EXIT /B 1



:Log

  set LEVEL=%~1

  set MSG=%~2

  echo [%DATE% %TIME:~0,8%] [%LEVEL%] %MSG%

  echo [%DATE% %TIME:~0,8%] [%LEVEL%] %MSG% >> "%LOG%"

EXIT /B

FOR ループ内で GOTO が使えない問題

FOR ループのブロック内(カッコ内)から GOTO を実行すると、FOR ループが中断されます。これは意図的な場合もありますが、ループを抜けずに次の繰り返しにスキップ(continue 相当)はできません。

:: NG例:FOR 内から GOTO でスキップしようとすると FOR ループ自体が終了する

for %%F in (*.txt) do (

  if "%%F"=="skip.txt" GOTO :NEXT_FILE   ← ループ全体が終わる!

  echo 処理: %%F

  :NEXT_FILE

)

回避策1:CALL :サブルーチン でラップする

@echo off

for %%F in (*.txt) do (

  CALL :ProcessFile "%%F"

)

GOTO :EOF



:ProcessFile

  if "%~1"=="skip.txt" EXIT /B    ← サブルーチンを抜けるだけ(FOR は継続)

  echo 処理: %~1

EXIT /B

回避策2:IF のネストで条件を反転する

for %%F in (*.txt) do (

  if NOT "%%F"=="skip.txt" (

    echo 処理: %%F

  )

)

FOR 内での制御フロー まとめ

GOTO(FOR 内から) → FOR ループ全体を終了(break 相当)

・continue 相当(特定ファイルをスキップ)→ CALL :サブルーチン + EXIT /B で実現

・条件を満たす場合のみ処理 → IF NOT でネスト

実務パターン3選

パターン1:メニュー選択(GOTO による分岐)

@echo off

:MENU

  echo ===========================

  echo  1. バックアップ実行

  echo  2. ログ確認

  echo  3. 終了

  echo ===========================

  set /P CHOICE=番号を入力: 



  if "%CHOICE%"=="1" GOTO :BACKUP

  if "%CHOICE%"=="2" GOTO :SHOW_LOG

  if "%CHOICE%"=="3" GOTO :EOF

  echo 無効な入力です

  GOTO :MENU



:BACKUP

  echo バックアップを実行します...

  GOTO :MENU



:SHOW_LOG

  type batch.log 2>nul || echo ログファイルがありません

  GOTO :MENU

パターン2:複数ファイルを CALL で処理(引数あり)

@echo off

setlocal



for %%F in (data*.csv) do (

  CALL :ProcessCsv "%%F"

)

echo 全ファイル処理完了

GOTO :EOF



:ProcessCsv

  set FILE=%~1

  set BASENAME=%~n1

  echo [処理] %BASENAME%.csv

  copy "%FILE%" "backup\%BASENAME%_%DATE:~0,4%%DATE:~5,2%%DATE:~8,2%.csv" >nul 2>&1

  if %ERRORLEVEL% NEQ 0 (

    echo [WARN] %BASENAME%.csv のバックアップ失敗

    EXIT /B 1

  )

EXIT /B 0

パターン3:引数の数に応じて分岐(CALL + 引数チェック)

@echo off

setlocal



:: コマンドライン引数で動作を変える

if "%~1"=="" GOTO :USAGE

if "%~1"=="/help" GOTO :USAGE

if "%~1"=="/run" CALL :RunProcess "%~2"

if "%~1"=="/check" CALL :CheckStatus

GOTO :EOF



:USAGE

  echo 使い方: batch.bat /run [ファイル名] または /check

  EXIT /B 1



:RunProcess

  echo 実行: %~1

  EXIT /B 0



:CheckStatus

  echo ステータス確認中...

  EXIT /B 0

よくある質問(FAQ)

❓ GOTO と CALL の使い分けを一言で言うと? (クリックで開閉)

GOTO = 行き先通行・戻らないCALL = 往復・戻ってくるです。

ループ・エラー処理へのジャンプ → GOTO、引数を受け取って結果を返す処理 → CALL :ラベル と覚えてください。

❓ ラベルに日本語は使える? (クリックで開閉)

技術的には使えますが、推奨しません。バッチファイルのエンコーディング(SJIS/UTF-8)や実行環境によって文字化けの原因になります。

ラベル名は 英数字+アンダースコア に統一するのがベストプラクティスです。

❓ CALL :ラベル と CALL バッチファイル名 の違いは? (クリックで開閉)

CALL :ラベル は同じバッチファイル内のラベルへジャンプして戻ります(サブルーチン)。

CALL other.bat は別のバッチファイルを実行して戻ります。いずれも実行後に呼び出し元に戻る点は同じです。

❓ GOTO :EOF と EXIT /B の違いは? (クリックで開閉)

GOTO :EOF はバッチ末尾へのジャンプで ERRORLEVEL を変更しません。

EXIT /B N は現在のコンテキストを終了して ERRORLEVEL に N をセットします。

戻り値を明示したいサブルーチン末尾は EXIT /B 0、メインの終了点は GOTO :EOF でも EXIT /B でもどちらでも構いません。統一することが重要です。

❓ 同じラベル名が2か所あるとどうなる? (クリックで開閉)

バッチファイルは最初に見つかったラベルにジャンプします。2つ目以降は無視されます。

ラベルの重複はデバッグが非常に難しくなるため、ラベル名はファイル内で必ず一意にしてください。

まとめ

命令 動作 引数 戻り値 主な用途
GOTO ラベル ジャンプ(戻らない) なし なし ループ・分岐・エラー処理
CALL :ラベル 呼び出し(EXIT /B で戻る) %1〜%9 ERRORLEVEL 再利用処理・関数的呼び出し
GOTO :EOF バッチ末尾にジャンプ 変更なし メイン終了・分岐後の終端
EXIT /B N 現コンテキスト終了 N を ERRORLEVEL にセット サブルーチン終了
:ラベル名 ジャンプ先マーカー GOTO/CALL の宛先定義

ラベル・GOTO・CALL は複雑に見えますが、「GOTO は一方通行、CALL は往復」という軸を押さえれば迷いません。まずはメイン末尾の GOTO :EOF、エラー処理の GOTO :ERROR、再利用処理の CALL :ログ出力 の3パターンを使いこなすだけでも、バッチファイルの品質は大きく向上します。