バッチファイルのexitとgoto :EOFの違い|画面が閉じる原因

バッチファイルのexitとgoto :EOFの違い|画面が閉じる原因

PR Amazonのアソシエイトとして、ITナレッジライフは適格販売により収入を得ています。

記事の文字数:4,995

バッチファイルの終了処理で使われる「exit」と「goto :EOF」の違いを徹底解説。意図せずコマンドプロンプト画面が閉じてしまう原因や、呼び出し元(call)への影響など、実務のバッチ作成で知っておくべき正しい使い分けをわかりやすく紹介します。

ITエンジニアにお勧めの本 ↗

おすすめ

エンジニアが知っておきたい思考の整理術 複雑な情報を【理解する】【伝える】テクニック

難易度
実用性
図解

思考の整理というテーマを、実務ですぐに使える具体的な「技術」として落とし込んだ一冊です。

ベストセラー

世界一流エンジニアの思考法

難易度
実用性
思考法

技術スキル以上に大切な「考え方」をアップデートできる。世界基準の効率的な仕事術が学べます。

文系社会人のためのIT資格の歩き方: 文系のあなたに最適な道をご提案します (YKcreate kiki)

難易度
実用性
キャリア度

ロードマップが非常に明確。キャリアプランを見据えた、無駄のない学習順序を提案してくれます。

エンジニアを説明上手にする本 相手に応じた技術情報や知識の伝え方

難易度
実用性
コミュ力

「伝える技術」もエンジニアの重要なスキル。相手の視点に立った、具体的な説明のコツが満載です。

技術広報入門 ー テックブログから始めるエンジニアカルチャーのつくり方

難易度
実用性
独自性

テックブログを入口にエンジニア組織の文化をどう設計し、育てていくかという実践論が学べます。

バッチファイルを作成しているとき、「処理を途中で終了させたいのに、黒いコマンドプロンプト画面自体が閉じてしまってデバッグできない」「他のバッチファイルから呼び出したときに挙動がおかしくなる」といったトラブルで困った経験はないでしょうか。

バッチファイルの終了処理には主に exit コマンドと goto :EOF という2つの方法がありますが、それぞれの挙動を正しく理解していないと、思わぬバグや作業効率の低下を招きます。

この記事を読むと、以下のメリットが得られます。

  • exit と goto :EOF の正確な挙動の違いを理解できる
  • コマンドプロンプトが意図せず閉じる原因と、それを防ぐ対策がわかる
  • 実務のバッチファイル設計において、どちらを選択すべきかの判断基準が明確になる

確認した環境

本記事の内容は、以下の環境で動作確認を行っています。

バッチファイルのexitとgoto :EOFの違いとは?基本の考え方

バッチファイル内で処理を中断・終了させたい場合、一般的に exit または goto :EOF が使用されます。しかし、この2つは「どこを終了させるのか」というスコープの概念において決定的な違いがあります。

  • exit: コマンドプロンプト(cmd.exe)のセッション自体を終了させる。/b を付けた場合に限り、現在のバッチファイルだけを終了する。
  • goto :EOF: コマンド拡張が有効な環境で使える特殊な指定。現在のバッチファイルの末尾へ制御を移して、そのバッチの実行のみを終了する。サブルーチン内で実行した場合は、呼び出し元に戻る。

まずはそれぞれの特徴と、実務で起こりがちなトラブルの原因について詳しく見ていきましょう。

バッチファイル(bat)のexitコマンドとは?使い方と注意点

exit は、コマンドプロンプトのインタプリタに対して「終了」を指示するコマンドです。バッチファイル専用の命令ではなく、コマンドプロンプトの機能の一部です。

基本的な構文は以下の通りです。

Terminal window
exit

オプションを指定しない場合、exit を実行したコマンドプロンプトのウィンドウ(セッション)そのものが閉じられます。

exit /bとは?バッチだけを終了して終了コードを返す方法

exit /b は、コマンドプロンプト自体を終了させずに、現在のバッチ処理だけを終了するための指定です。/b は Batch の意味です。

  • バッチファイルのメイン処理で実行すると、そのバッチファイルの実行を終了します。
  • call :SubRoutine で呼び出されたサブルーチン内で実行すると、サブルーチンを終了して呼び出し元へ戻ります。
  • exit /b 1 のように数値を指定すると、ERRORLEVEL にその値を設定して終了します。
  • 数値を省略した exit /b は、ERRORLEVEL を変更せず、直前の値を維持します。
Terminal window
@echo off
echo 処理を開始します。
if "%1"=="" (
echo 引数が指定されていないため、処理を中断します。
exit /b 1
)
echo 引数は正常に指定されています: %1

exit /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 で呼び出されたサブルーチン内で実行した場合は、そのサブルーチンから呼び出し元へ処理が戻ります。

Terminal window
@echo off
echo 処理1
goto :EOF
echo この行は実行されません

上記のスクリプトを、すでに開いているコマンドプロンプトから実行した場合、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)の違いが重要になります。

以下のサンプルコードを確認してください。

Terminal window
@echo off
echo メイン処理を開始します。
call :SubRoutine
echo メイン処理を継続します。
goto :EOF
:SubRoutine
echo サブルーチン内の処理です。
REM ここで終了したい場合
exit /b 0

上記の例で SubRoutine 内に通常の exit や exit /b を記述した場合の挙動は以下のようになります。

  1. exit(オプションなし)を使用した場合: サブルーチンだけでなく、バッチファイル全体、さらには実行中のコマンドプロンプトウィンドウ自体が終了して閉じられます。
  2. exit /b を使用した場合: サブルーチンの実行のみが終了し、呼び出し元の call :SubRoutine の次の行(echo メイン処理を継続します。)に正しく処理が戻ります。
  3. goto :EOF を使用した場合: call で呼び出されたサブルーチン内で実行すると、call の呼び出し元へ処理が戻ります(exit /b と同様の動作です)。

exit /b 3 は ERRORLEVEL を 3 に設定して終了します。一方、goto :EOF と数値を省略した exit /b は、現在の ERRORLEVEL を維持します。

違いを確認するサンプルは次の通りです。

Terminal window
@echo off
call :KeepError
echo KeepError 復帰後: %ERRORLEVEL%
call :SetZero
echo SetZero 復帰後: %ERRORLEVEL%
goto :EOF
:KeepError
cmd /c exit 5
goto :EOF
:SetZero
exit /b 0

このサンプルの cmd /c exit 5 は、外部コマンドが終了コード 5 で失敗した状態を再現するための疑似的な処理です。実際のバッチでは、外部コマンドを実行した直後に %ERRORLEVEL% を確認してから終了するようにしてください。

実行すると、goto :EOF で戻った直後は直前の 5 が維持され、exit /b 0 で戻った直後は 0 に設定されます。

KeepError 復帰後: 5
SetZero 復帰後: 0

そのため、処理が失敗した直後に goto :EOF で終了すると、直前の処理が設定したエラーコードが残る場合があります。正常終了として 0 を明示的に返したい場合は exit /b 0 を使用してください。

サブルーチンからの抜け道としては、goto :EOF と exit /b のどちらも使えます。

[!NOTE] サブルーチン内で setlocal を使っている場合、exit /b や goto :EOF で戻ると暗黙の endlocal が実行され、そのサブルーチン内で設定した変数は呼び出し元に残りません。サブルーチンで作った値を呼び出し元に返したいときは、次のように endlocal と同じ行で set します。

Terminal window
@echo off
call :GetValue
echo RESULT=[%RESULT%]
goto :EOF
:GetValue
setlocal
set "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のおすすめの使い分け

  1. 通常の終了やサブルーチンからの復帰は goto :EOF または exit /b
    どちらも現在のバッチ処理を終了でき、exit(オプションなし)のようにセッションごと閉じてしまうリスクもありません。チーム内やプロジェクト内で方針を統一すると保守しやすくなります。
  2. 終了コードを明示したいときは exit /b 数値
    exit /b 0 や exit /b 1 を使うと、後続のバッチ処理や呼び出し元で成功・失敗を判定しやすくなります。他のバッチファイルやCI/CDCI/CD [シーアイシーディー]継続的インテグレーション/継続的デリバリーツール、タスクスケジューラーから呼び出す場合に適しています。
  3. コマンドプロンプト自体を終了させたいときだけ exit
    既存のコマンドプロンプトから実行された場合は、呼び出し元のセッションまで閉じてしまうため、トップレベルでの使用は極力避けます。
  4. ダブルクリック実行時に結果を確認したいときは pause
    どの終了方法でも処理後に画面が閉じるため、結果を確認したい場合は終了前に pause を挟みます。ただし、無人実行では入力待ちで止まるため、常に入れるのは避けてください。

まとめ:バッチファイルの正しい終了方法

本記事では、バッチファイルの終了処理における exit と goto :EOF の違いや、コマンドプロンプトが閉じる原因について解説しました。

記事のポイントを以下にまとめます。

  • オプションなしの exit はコマンドプロンプトのセッション自体を終了させるため、既存のプロンプトから実行したバッチで使うとウィンドウごと閉じてしまう。
  • ダブルクリック実行では、exit の有無に関係なく、処理が終われば画面は閉じる。結果を確認するには pause が必要。
  • exit /b を使うことで、セッションを閉じずに終了コード(ERRORLEVEL)を指定してバッチを終了できる。数値を省略した場合は、直前の ERRORLEVEL が維持される。
  • goto :EOF はコマンド拡張が有効な環境で使える特殊な指定で、現在のスクリプトスコープ(またはサブルーチン)を終了し、ERRORLEVEL を変更せずに処理を抜けることができる。
  • 通常の終了やサブルーチンからの復帰には goto :EOF と exit /b のどちらも使える。終了コードを明示したい場合は exit /b 数値 を選ぶ。

以上で本記事の解説を終わります。
よいITライフを!
ITナレッジライフ 運営者
この記事を書いた人

Z (ITナレッジライフ)

現役のITエンジニア。Linux、プログラミング、IT用語など、日々の業務で得た「痒いところに手が届く」技術情報を発信しています。

プロフィールと編集ポリシーを見る →

ITエンジニアにお勧めの本 ↗

おすすめ

エンジニアが知っておきたい思考の整理術 複雑な情報を【理解する】【伝える】テクニック

難易度
実用性
図解

思考の整理というテーマを、実務ですぐに使える具体的な「技術」として落とし込んだ一冊です。

人気記事


記事を評価

Thanks!
目次
Scroll to Top