【bat】pause が効かない・一瞬で閉じるときの原因と対処法完全ガイド|6つの原因・デバッグ方法・確実に止めるテンプレートまで

【bat】pause が効かない/一瞬で閉じてしまうときの原因と対処法 bat

バッチファイルの最後に 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 なしで別バッチを呼び出すと、コマンドインタプリタがそのバッチファイルに「ジャンプ」します。別バッチが終了すると、コマンドインタプリタはそこで実行すべきコマンドがなくなったと判断してウィンドウを閉じます。call を使うと呼び出し元への「戻りアドレス」が保存されるため、別バッチ終了後に元のバッチに戻れます。

原因2:exit で終了している(exit /b を使うべき)

exitexit /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

原因3:エラー処理で pause がスキップされる

エラーが発生したとき、エラー処理ブロックで goto :eofexit /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
ERRORLEVELを使ったエラーハンドリングの詳細は【bat】ERRORLEVELを使ってエラーハンドリングを行う方法を参照。

原因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
VSCodeやサクラエディタなどのテキストエディタの括弧マッチング機能を使うと、対応する括弧をハイライト表示してくれるため確認しやすくなります。また、バッチを実行せずに構文確認だけしたい場合は 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 で止まります。

タスクスケジューラからの実行時の問題全般は【bat】タスクスケジューラから実行したときだけ動作が異なる原因と解決策を参照。

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 を入れて実行し、どこまで到達しているかを特定しましょう。
pause はあるのに「続行するには…」が表示されず閉じる
pause の前の行に exit(/b なし)が実行されている可能性が高いです。すべての exitexit /b に変更してください。また、goto :eof が pause より前に実行されていないかも確認してください。
エラー時だけウィンドウが閉じる
エラー処理ブロック(if %ERRORLEVEL% neq 0)の中に exitgoto :eof があり、pause をスキップしている可能性があります。エラーブロックの中にも pause を入れるか、:finally テンプレートを使ってすべてのルートで pause を通過するようにしましょう。
call を付けているのに pause が効かない
call した先のバッチ(sub.bat)の中で exit(/b なし)を実行している可能性があります。call 先のバッチを確認し、exitexit /b に修正してください。call 先の exit は呼び出し元も含めた cmd.exe 全体を終了させます。
タスクスケジューラで実行するときは pause を入れないほうがいい?
はい、タスクスケジューラから実行するバッチには pause は入れないのが原則です(キー入力待ちでタスクが終了しなくなります)。手動実行とタスクスケジューラの両方に対応するには、/nopause 引数でスキップする仕組みを入れるか、手動実行専用のバッチと自動実行専用のバッチを分けるのが推奨です。

まとめ

原因 症状 対処法
call なしで別バッチを呼んでいる 制御が戻らず pause に到達しない call sub.bat に修正
exit で終了している cmd.exe ごと終了してウィンドウが閉じる exit /b に変更
エラー処理で pause をスキップ エラー時だけ閉じる エラーブロックにも pause を追加・:finally テンプレート使用
括弧ブロックの構文エラー pause を含む後続行が実行されない 括弧の対応を確認・エディタのマッチング機能を活用
パイプ・リダイレクト経由で実行 pause がキー入力を受け付けない pause >nul <CON を使う
タスクスケジューラから実行 ウィンドウが表示されない /nopause 引数でスキップする仕組みを入れる
確実に pause を効かせる4つのコツ
1. 別バッチの呼び出しには必ず call を付ける
2. exit ではなく exit /b を使う
3. 正常系・異常系のすべてのルートで pause を通す(:finally テンプレート活用)
4. タスクスケジューラ・パイプ経由の場合は timeout<CON で対応する

あわせて読みたい