バッチファイルを作成しているとき、「処理を途中で終了させたいのに、黒いコマンドプロンプト画面自体が閉じてしまってデバッグできない」「他のバッチファイルから呼び出したときに挙動がおかしくなる」といったトラブルで困った経験はないでしょうか。
バッチファイルの終了処理には主に exit コマンドと goto :EOF という2つの方法がありますが、それぞれの挙動を正しく理解していないと、思わぬバグや作業効率の低下を招きます。
この記事を読むと、以下のメリットが得られます。
exitとgoto :EOFの正確な挙動の違いを理解できる- コマンドプロンプトが意図せず閉じる原因と、それを防ぐ対策がわかる
- 実務のバッチファイル設計において、どちらを選択すべきかの判断基準が明確になる
確認した環境
本記事の内容は、以下の環境で動作確認を行っています。
- OSOS [オーエス]Operating System。基本ソフトウェア: Windows 11
- シェル: コマンドプロンプト (
cmd.exe)
バッチファイルのexitとgoto :EOFの違いとは?基本の考え方
バッチファイル内で処理を中断・終了させたい場合、一般的に exit または goto :EOF が使用されます。しかし、この2つは「どこを終了させるのか」というスコープの概念において決定的な違いがあります。
exit: コマンドプロンプト(cmd.exe)のセッション自体を終了させる。/bを付けた場合に限り、現在のバッチファイルだけを終了する。goto :EOF: コマンド拡張が有効な環境で使える特殊な指定。現在のバッチファイルの末尾へ制御を移して、そのバッチの実行のみを終了する。サブルーチン内で実行した場合は、呼び出し元に戻る。
まずはそれぞれの特徴と、実務で起こりがちなトラブルの原因について詳しく見ていきましょう。
バッチファイル(bat)のexitコマンドとは?使い方と注意点
exit は、コマンドプロンプトのインタプリタに対して「終了」を指示するコマンドです。バッチファイル専用の命令ではなく、コマンドプロンプトの機能の一部です。
基本的な構文は以下の通りです。
exitオプションを指定しない場合、exit を実行したコマンドプロンプトのウィンドウ(セッション)そのものが閉じられます。
exit /bとは?バッチだけを終了して終了コードを返す方法
exit /b は、コマンドプロンプト自体を終了させずに、現在のバッチ処理だけを終了するための指定です。/b は Batch の意味です。
- バッチファイルのメイン処理で実行すると、そのバッチファイルの実行を終了します。
call :SubRoutineで呼び出されたサブルーチン内で実行すると、サブルーチンを終了して呼び出し元へ戻ります。exit /b 1のように数値を指定すると、ERRORLEVEL にその値を設定して終了します。- 数値を省略した
exit /bは、ERRORLEVEL を変更せず、直前の値を維持します。
@echo offecho 処理を開始します。if "%1"=="" ( echo 引数が指定されていないため、処理を中断します。 exit /b 1)echo 引数は正常に指定されています: %1exit /b を使用するメリットは以下の通りです。
- cmd.exe を終了させない: バッチファイル内で実行した場合、
cmd.exe自体は終了しない。エディタのターミナルや手動で開いたコマンドプロンプトからバッチを実行した際、画面が維持されるためエラーログを目視で確認できる。 - 終了コード(ERRORLEVEL)を設定できる:
/bの後に数値(例:exit /b 1)を指定することで、呼び出し元のバッチファイルに対して成功(0)か失敗(1など)のステータスを返せる。
[!NOTE] タスクスケジューラーなど、外部のプログラムに終了結果を伝える場合は、バッチの呼び出し方や呼び出し元の実装も関係します。終了コードを確実に渡したいときは、
exit /b 数値で明示的に指定してください。
exitでコマンドプロンプトが閉じる原因とダブルクリック実行時の注意点
すでに開いているコマンドプロンプトからバッチファイルを実行し、その中でオプションなしの exit が実行されると、バッチファイルだけでなく、そのコマンドプロンプトのウィンドウ自体が閉じられます。これは exit が cmd.exe 自体を終了させるコマンドだからです。
なお、exit /b はバッチファイル内で実行すれば、そのバッチだけを終了します。ただし、バッチファイルの外(プロンプトへの直接入力など)で実行した場合は、cmd.exe が終了します。
[!NOTE] デスクトップ上のバッチファイルをダブルクリックして実行した場合は、
exitの有無に関係なく、バッチファイルの処理が終わると黒い画面は閉じます。これはgoto :EOFやexit /bで終了した場合や、ファイルの末尾まで到達した場合も同様です。ダブルクリック時に結果を画面に残したい場合は、終了処理の前にpauseを入れてください。ただし
pauseはキー入力を待つため、タスクスケジューラーなどの無人実行では処理が止まります。常に入れるのではなく、手動実行のデバッグ時に限って使うのが安全です。デバッグ時は、既存のコマンドプロンプトから実行する方法も有効です。
goto :EOFとは?バッチファイルを安全に終了する方法
goto :EOF は、コマンド拡張が有効な環境で使用できる特殊な指定です。ファイル内に :EOF というラベルを定義する必要はありません。実行すると、現在のバッチファイルの末尾へ制御が移り、バッチファイルの実行が終了します。
また、call :SubRoutine で呼び出されたサブルーチン内で実行した場合は、そのサブルーチンから呼び出し元へ処理が戻ります。
@echo offecho 処理1goto :EOFecho この行は実行されません上記のスクリプトを、すでに開いているコマンドプロンプトから実行した場合、goto :EOF に到達した時点でバッチファイルの実行が終了し、コマンドプロンプトのウィンドウは閉じずに開いたまま維持されます。
goto :EOF のコロンは必須です。コロンを付けずに goto EOF と書くと、EOF という名前の通常のラベルを探すため、ラベルが見つからないというエラーになります。また、:EOF を使うにはコマンド拡張が有効である必要があります(既定で有効)。
goto :EOF の大きなメリットは以下の通りです。
- セッションが維持される: 既存のコマンドプロンプトから実行した場合、スクリプトの途中で抜けても、コマンドプロンプトのセッションが維持される。
- 安全な終了: ウィンドウや親プロセスを強制終了させず、現在のバッチスコープの実行を穏やかに終了できる。
- ERRORLEVELを変更しない:
goto :EOFは ERRORLEVEL を設定しないため、直前の値がそのまま残る。
callでサブルーチンを呼ぶとき、exit・exit /b・goto :EOFはどう違う?
バッチファイル内で call コマンドを使用してサブルーチン(ラベル)を呼び出す場合、exit(オプションなし)とそれ以外の終了方法(exit /b、goto :EOF)の違いが重要になります。
以下のサンプルコードを確認してください。
@echo offecho メイン処理を開始します。call :SubRoutineecho メイン処理を継続します。goto :EOF
:SubRoutineecho サブルーチン内の処理です。REM ここで終了したい場合exit /b 0上記の例で SubRoutine 内に通常の exit や exit /b を記述した場合の挙動は以下のようになります。
exit(オプションなし)を使用した場合: サブルーチンだけでなく、バッチファイル全体、さらには実行中のコマンドプロンプトウィンドウ自体が終了して閉じられます。exit /bを使用した場合: サブルーチンの実行のみが終了し、呼び出し元のcall :SubRoutineの次の行(echo メイン処理を継続します。)に正しく処理が戻ります。goto :EOFを使用した場合:callで呼び出されたサブルーチン内で実行すると、callの呼び出し元へ処理が戻ります(exit /bと同様の動作です)。
exit /b 3 は ERRORLEVEL を 3 に設定して終了します。一方、goto :EOF と数値を省略した exit /b は、現在の ERRORLEVEL を維持します。
違いを確認するサンプルは次の通りです。
@echo offcall :KeepErrorecho KeepError 復帰後: %ERRORLEVEL%call :SetZeroecho SetZero 復帰後: %ERRORLEVEL%goto :EOF
:KeepErrorcmd /c exit 5goto :EOF
:SetZeroexit /b 0このサンプルの cmd /c exit 5 は、外部コマンドが終了コード 5 で失敗した状態を再現するための疑似的な処理です。実際のバッチでは、外部コマンドを実行した直後に %ERRORLEVEL% を確認してから終了するようにしてください。
実行すると、goto :EOF で戻った直後は直前の 5 が維持され、exit /b 0 で戻った直後は 0 に設定されます。
KeepError 復帰後: 5SetZero 復帰後: 0そのため、処理が失敗した直後に goto :EOF で終了すると、直前の処理が設定したエラーコードが残る場合があります。正常終了として 0 を明示的に返したい場合は exit /b 0 を使用してください。
サブルーチンからの抜け道としては、goto :EOF と exit /b のどちらも使えます。
[!NOTE] サブルーチン内で
setlocalを使っている場合、exit /bやgoto :EOFで戻ると暗黙のendlocalが実行され、そのサブルーチン内で設定した変数は呼び出し元に残りません。サブルーチンで作った値を呼び出し元に返したいときは、次のようにendlocalと同じ行でsetします。
@echo offcall :GetValueecho RESULT=[%RESULT%]goto :EOF
:GetValuesetlocalset "RESULT=hello"endlocal & set "RESULT=%RESULT%"exit /b 0
%RESULT%は行の実行前に展開されるため、endlocalで変数が消えた後でも、展開済みの値を呼び出し元で設定できます。
バッチファイルはexit /bとgoto :EOFのどちらを使う?比較表と判断基準
実務でバッチファイルを作成・運用するにあたり、どちらのコマンドを選択すべきかの判断基準を以下に整理します。
| 項目 | exit /b [終了コード] | goto :EOF |
|---|---|---|
| 主な用途 | バッチ処理の終了、サブルーチンからの復帰 | バッチ処理の終了、サブルーチンからの復帰 |
| ERRORLEVEL | 数値指定時はその値に設定。省略時は直前の値を維持 | 直前の値を維持 |
| 終了コードの明示指定 | 可能 | 不可 |
| cmd.exe の終了 | バッチ内では終了しない | 終了しない |
| コマンド拡張 | 不要 | 有効にする必要がある(既定で有効) |
exit・exit /b・goto :EOFのおすすめの使い分け
- 通常の終了やサブルーチンからの復帰は
goto :EOFまたはexit /b
どちらも現在のバッチ処理を終了でき、exit(オプションなし)のようにセッションごと閉じてしまうリスクもありません。チーム内やプロジェクト内で方針を統一すると保守しやすくなります。 - 終了コードを明示したいときは
exit /b 数値
exit /b 0やexit /b 1を使うと、後続のバッチ処理や呼び出し元で成功・失敗を判定しやすくなります。他のバッチファイルやCI/CDCI/CD [シーアイシーディー]継続的インテグレーション/継続的デリバリーツール、タスクスケジューラーから呼び出す場合に適しています。 - コマンドプロンプト自体を終了させたいときだけ
exit
既存のコマンドプロンプトから実行された場合は、呼び出し元のセッションまで閉じてしまうため、トップレベルでの使用は極力避けます。 - ダブルクリック実行時に結果を確認したいときは
pause
どの終了方法でも処理後に画面が閉じるため、結果を確認したい場合は終了前にpauseを挟みます。ただし、無人実行では入力待ちで止まるため、常に入れるのは避けてください。
まとめ:バッチファイルの正しい終了方法
本記事では、バッチファイルの終了処理における exit と goto :EOF の違いや、コマンドプロンプトが閉じる原因について解説しました。
記事のポイントを以下にまとめます。
- オプションなしの
exitはコマンドプロンプトのセッション自体を終了させるため、既存のプロンプトから実行したバッチで使うとウィンドウごと閉じてしまう。 - ダブルクリック実行では、
exitの有無に関係なく、処理が終われば画面は閉じる。結果を確認するにはpauseが必要。 exit /bを使うことで、セッションを閉じずに終了コード(ERRORLEVEL)を指定してバッチを終了できる。数値を省略した場合は、直前の ERRORLEVEL が維持される。goto :EOFはコマンド拡張が有効な環境で使える特殊な指定で、現在のスクリプトスコープ(またはサブルーチン)を終了し、ERRORLEVEL を変更せずに処理を抜けることができる。- 通常の終了やサブルーチンからの復帰には
goto :EOFとexit /bのどちらも使える。終了コードを明示したい場合はexit /b 数値を選ぶ。
以上で本記事の解説を終わります。
よいITライフを!
人気記事
- 1
- 2
- 3
- 4
- 5
思考の整理というテーマを、実務ですぐに使える具体的な「技術」として落とし込んだ一冊です。