バッチファイルの最後に pause を入れているのに、画面が一瞬で閉じてしまう——この現象は「pause に到達する前に処理が終了している」ことが原因です。
この記事では、pause が効かない・一瞬で閉じる6つの原因とそれぞれの具体的な対処法、どのルートでも確実に pause が実行されるテンプレートを解説します。
・pause が効かない・一瞬で閉じる6つの原因と対処法
・どの時点でウィンドウが閉じているかを特定するデバッグ方法
・exit と exit /b の違い(最もよくある間違い)
・タスクスケジューラ実行時に pause をスキップする方法
・timeout・set /p・cmd /k などの代替コマンド
・すべてのルートで必ず pause が実行される :finally テンプレート
まず:どこで閉じているかを特定するデバッグ方法
原因を特定する前に、バッチのどの行まで実行されているかを確認しましょう。
@echo off echo [DEBUG] Step 1 到達 call sub.bat echo [DEBUG] Step 2 到達(sub.bat 終了後) echo [DEBUG] Step 3 到達 pause
echo [DEBUG] Step N を各ポイントに入れて実行すると、どの行まで到達しているかが分かります。「Step 1 到達」は表示されるが「Step 2 到達」は表示されない場合、call sub.bat の行で処理が戻ってきていないことがわかります。
@echo on(echo offを外す)にすると、実行したコマンドがすべて表示されます。どのコマンドが最後に実行されたかを見れば、どこで止まっているかが分かります。原因1:call なしで別のバッチを呼んでいる(最も多い原因)
最も多い原因がこれです。バッチファイルから別のバッチファイルを call なしで呼び出すと、呼び出し元に処理が戻りません。
rem NG: call なし → sub.bat が終了するとそのまま cmd.exe が終了 @echo off echo メイン処理を開始します。 sub.bat ← ここで制御が移りっぱなしになる echo この行は実行されない! pause
rem OK: call あり → sub.bat 終了後にメインに戻る @echo off echo メイン処理を開始します。 call sub.bat ← sub.bat 終了後にメインに戻る echo この行は実行される! pause
call なしで別バッチを呼び出すと、コマンドインタプリタがそのバッチファイルに「ジャンプ」します。別バッチが終了すると、コマンドインタプリタはそこで実行すべきコマンドがなくなったと判断してウィンドウを閉じます。
call を使うと呼び出し元への「戻りアドレス」が保存されるため、別バッチ終了後に元のバッチに戻れます。原因2:exit で終了している(exit /b を使うべき)
exit と exit /b はまったく異なる動作をします。
| コマンド | 動作 | ウィンドウ |
|---|---|---|
exit |
cmd.exe 自体を終了する | 閉じる |
exit /b |
現在のバッチファイルだけを終了する | 残る(親バッチや cmd.exe は継続) |
exit /b 0 |
正常終了コード0で現在のバッチを終了 | 残る |
exit /b 1 |
エラーコード1で現在のバッチを終了 | 残る |
rem NG: exit を使うと cmd.exe ごと終了してウィンドウが閉じる
@echo off
if %ERRORLEVEL% neq 0 (
echo エラーが発生しました。
exit ← cmd.exe ごと終了!pause に到達しない
)
pause
rem OK: exit /b を使い、エラー時にも pause を経由する
@echo off
if %ERRORLEVEL% neq 0 (
echo エラーが発生しました。
pause
exit /b 1 ← バッチのみ終了、ウィンドウは残る
)
echo 正常終了
pause
exit /b の詳細な挙動は【bat】exit /b の使い方を誤って予期せぬ終了になるときの修正方法を参照。原因3:エラー処理で pause がスキップされる
エラーが発生したとき、エラー処理ブロックで goto :eof や exit /b を実行すると、正常終了時の pause を飛ばしてしまいます。
rem NG: エラー時の goto :eof が pause をスキップする
@echo off
xcopy C:\data\*.* C:\backup\ /E /Y
if %ERRORLEVEL% neq 0 (
echo エラーが発生しました。
goto :eof ← pause をスキップして終了
)
echo 処理完了
pause
rem OK: エラー時にも pause を通す
@echo off
xcopy C:\data\*.* C:\backup\ /E /Y
if %ERRORLEVEL% neq 0 (
echo エラーコード: %ERRORLEVEL%
pause ← エラー時にも一時停止
exit /b 1
)
echo 処理完了
pause
原因4:括弧ブロックの構文エラーで pause がスキップされる
if 文や for 文の括弧の対応が崩れると、バッチインタプリタが構文エラーを起こし、pause を含む後続の行が実行されません。
rem NG: 括弧の閉じ忘れ
@echo off
if exist file.txt (
echo ファイルあり
if %ERRORLEVEL% equ 0 (
echo 正常
)
rem ← 外側の ) が足りない!
pause
rem OK: 括弧の対応が正しい
@echo off
if exist file.txt (
echo ファイルあり
if %ERRORLEVEL% equ 0 (
echo 正常
)
)
pause
cmd /c "バッチファイル" 2>&1 | more で構文エラーを確認できます。原因5:パイプやリダイレクト経由で実行すると pause が効かない
バッチファイルをパイプ(|)やリダイレクト(<)経由で実行すると、pause がキー入力を受け付けられない場合があります。pause は標準入力(キーボード)からの入力を待つコマンドであるため、標準入力がパイプやファイルに切り替わっていると待機できません。
rem パイプ経由だと pause が効かない echo test | test.bat rem リダイレクト経由でも同様 test.bat < input.txt
rem 対処法: <CON でコンソールから直接入力を受ける @echo off echo 処理結果を表示します。 echo 続行するには何かキーを押してください . . . pause >nul <CON
<CON を付けることで、標準入力の状態に関わらずコンソール(キーボード)から直接入力を受け取ります。パイプやリダイレクト経由で実行されるバッチに pause を入れる場合は常にこの形式を使いましょう。原因6:タスクスケジューラから実行している
タスクスケジューラから実行されたバッチファイルにはコンソールウィンドウが表示されないため、pause は無意味です。キー入力を待ち続けてタスクが完了しません(タイムアウトまで止まる)。
rem 対処法: 引数でpauseをスキップする仕組みを入れる @echo off echo 処理を実行します。 xcopy C:\data\*.* C:\backup\ /E /Y rem 引数 /nopause が指定された場合は pause をスキップ if "%1"=="/nopause" goto :end pause :end exit /b 0
タスクスケジューラの「引数の追加(オプション)」に /nopause を設定すれば、自動実行時は pause をスキップし、手動実行時は pause で止まります。
pause の代わりに使える代替コマンド
timeout(秒数指定で自動続行)
rem 10秒待機(キー押下で即続行) timeout /t 10 rem 10秒待機(キー入力を無視・タスクスケジューラでも止まらない) timeout /t 10 /nobreak rem 無限待機(pause と同じ効果) timeout /t -1
timeout は指定秒数後に自動で続行するため、タスクスケジューラから実行しても処理が永久に止まりません。詳細は【bat】バッチファイルで処理を一時停止する方法完全ガイドを参照。
set /p(カスタムメッセージで一時停止)
rem pause のデフォルトメッセージを変更したい場合 set /p =Enterキーを押すと終了します...<nul rem 変数にも利用できる(入力内容は使わない場合はダミー変数) set /p _dummy=処理が完了しました。Enterで閉じます...
cmd /k(ウィンドウを閉じない)
rem ショートカットのリンク先に設定する例 cmd /k C:\scripts\test.bat rem バッチ内でウィンドウを継続する場合 cmd /k "echo 処理が完了しました。このウィンドウを閉じてください。"
cmd /k はバッチ実行後もコマンドプロンプトを開いたままにします。ショートカットのプロパティで cmd /k バッチ名 と設定すると便利です。
代替コマンドの比較
| コマンド | 待機方法 | タスクスケジューラ | カスタムメッセージ | 主な用途 |
|---|---|---|---|---|
pause |
キー押下まで | 動かない(無限待機) | 不可 | 手動実行バッチ |
timeout /t N |
N秒後or キー押下 | 問題なし | 不可 | 確認後に自動続行 |
timeout /t -1 |
キー押下まで | 動かない | 不可 | pause の代替 |
set /p |
Enter押下まで | 動かない | 可 | メッセージを変えたい場合 |
cmd /k |
ウィンドウを維持 | 非推奨 | 不可 | ショートカット経由 |
確実に pause を効かせる :finally テンプレート
すべての処理ルートを :finally ラベルに集約することで、正常終了・異常終了どちらでも必ず pause が実行されます。
@echo off
setlocal
echo === 処理開始 ===
rem --- メイン処理 ---
xcopy C:\data\*.* C:\backup\ /E /Y
if %ERRORLEVEL% neq 0 (
echo [エラー] ファイルコピーに失敗しました。コード: %ERRORLEVEL%
set RESULT=1
goto :finally
)
echo [成功] 処理が完了しました。
set RESULT=0
:finally
echo === 処理終了(コード: %RESULT%)===
endlocal
pause
exit /b %RESULT%
・すべての処理ルートが
:finally に集約されるため、pause の書き漏れがなくなる・
set RESULT=0/1 で終了コードを統一管理できる・
setlocal / endlocal で変数をスコープ内に閉じ込める・タスクスケジューラや
/nopause 引数への対応も追加しやすいよくある質問
pause が書かれているかを確認してください。書いてある場合は「原因1〜6」のいずれかで pause に到達していない可能性があります。デバッグ方法として、バッチの各ステップに echo [DEBUG] Step N を入れて実行し、どこまで到達しているかを特定しましょう。exit(/b なし)が実行されている可能性が高いです。すべての exit を exit /b に変更してください。また、goto :eof が pause より前に実行されていないかも確認してください。if %ERRORLEVEL% neq 0)の中に exit や goto :eof があり、pause をスキップしている可能性があります。エラーブロックの中にも pause を入れるか、:finally テンプレートを使ってすべてのルートで pause を通過するようにしましょう。exit(/b なし)を実行している可能性があります。call 先のバッチを確認し、exit を exit /b に修正してください。call 先の exit は呼び出し元も含めた cmd.exe 全体を終了させます。pause は入れないのが原則です(キー入力待ちでタスクが終了しなくなります)。手動実行とタスクスケジューラの両方に対応するには、/nopause 引数でスキップする仕組みを入れるか、手動実行専用のバッチと自動実行専用のバッチを分けるのが推奨です。まとめ
| 原因 | 症状 | 対処法 |
|---|---|---|
| call なしで別バッチを呼んでいる | 制御が戻らず pause に到達しない | call sub.bat に修正 |
exit で終了している |
cmd.exe ごと終了してウィンドウが閉じる | exit /b に変更 |
| エラー処理で pause をスキップ | エラー時だけ閉じる | エラーブロックにも pause を追加・:finally テンプレート使用 |
| 括弧ブロックの構文エラー | pause を含む後続行が実行されない | 括弧の対応を確認・エディタのマッチング機能を活用 |
| パイプ・リダイレクト経由で実行 | pause がキー入力を受け付けない | pause >nul <CON を使う |
| タスクスケジューラから実行 | ウィンドウが表示されない | /nopause 引数でスキップする仕組みを入れる |
1. 別バッチの呼び出しには必ず
call を付ける2.
exit ではなく exit /b を使う3. 正常系・異常系のすべてのルートで pause を通す(:finally テンプレート活用)
4. タスクスケジューラ・パイプ経由の場合は
timeout や <CON で対応する

