HOWTO · Batch
Windowsバッチファイルでコマンドやexeの終了を待つ方法
通常のコマンドは順番に実行されます。別のバッチは CALL、START で起動したプログラムは START "" /WAIT を使い、終了コードを確認する方法を解説します。
このページの内容
Windows のバッチファイルでは、通常のコマンドや直接指定した .exe は、終了してから次の行へ進みます。そのため、直接実行できるプログラムに START /WAIT を付ける必要はありません。
別のバッチファイルを実行して呼び出し元へ戻るには CALL、プログラムを START で起動しつつ終了を待つには START "" /WAIT を使います。待機直後の %ERRORLEVEL% を保存すれば、後続処理で終了コードを判定できます。
| 実行したいもの | 適切な書き方 | 待機の意味 |
|---|---|---|
通常のコマンド、直接起動する .exe |
program.exe |
プログラムが戻るまで次の行へ進まない |
別の .bat または .cmd |
call child.cmd |
子バッチの終了後、CALL の次の行へ戻る |
START で起動するプログラム |
start "" /wait program.exe |
START が起動したプロセスの終了を待つ |
| 一定時間、またはキー入力 | timeout または pause |
プロセスの完了ではなく、時間または入力を待つ |
通常のコマンドやexeは直接実行する
次の例では ping.exe を直接実行しています。[2] は ping が戻った後にだけ表示されます。
@echo off
echo [1] ping start
ping 127.0.0.1 -n 2 >nul
set "rc=%ERRORLEVEL%"
echo [2] ping end: exit code=%rc%
exit /b %rc%
出力は次の順序になります。
[1] ping start
[2] ping end: exit code=0
ERRORLEVEL は別のコマンドによって変わることがあるため、対象コマンドの直後に set "rc=%ERRORLEVEL%" で保存します。
別のバッチファイルはCALLで呼び出す
バッチファイルから別のバッチファイルを名前だけで実行すると、通常は呼び出し元へ戻りません。Microsoft の CALL の説明に従い、子バッチの終了を待って次の行へ戻る場合は CALL を使います。
まず、次の内容を child.cmd として保存します。
@echo off
echo [child] start
ping 127.0.0.1 -n 2 >nul
echo [child] end
exit /b 7
同じフォルダーに、呼び出し元の parent.cmd を作成します。
@echo off
echo [parent] before call
call child.cmd
set "rc=%ERRORLEVEL%"
echo [parent] after call: exit code=%rc%
exit /b %rc%
parent.cmd を実行すると、子バッチの出力が終わった後に親バッチの処理が再開し、終了コード 7 も引き継がれます。
引数は call child.cmd input.txt のように子ファイル名の後ろへ渡します。空白を含む引数は引用符で囲みますが、親へ戻る目的で子バッチを START から起動する必要はありません。
[parent] before call
[child] start
[child] end
[parent] after call: exit code=7
STARTを使う場合は"" /WAITを付ける
別ウィンドウや別プロセスとして起動する目的で START を選んだ場合は、/WAIT を指定します。Microsoft の START の構文では、最初の引用符付き引数はウィンドウタイトルとして扱われます。実行ファイルのパスを引用符で囲むときは、その前に空のタイトル "" が必要です。
次の自己完結した例は、空白を含む一時フォルダーへ cmd.exe のコピーを作り、そのコピーが終了するまで待ちます。
@echo off
setlocal
set "work=%TEMP%\DelftStack Wait Test"
if not exist "%work%" mkdir "%work%"
copy /y "%ComSpec%" "%work%\worker.exe" >nul
echo [parent] before start
start "" /b /wait "%work%\worker.exe" /d /c "ping 127.0.0.1 -n 2 >nul & exit /b 9"
set "rc=%ERRORLEVEL%"
echo [parent] after start: exit code=%rc%
del "%work%\worker.exe"
rmdir "%work%"
exit /b %rc%
実行結果は次のようになります。after start は、起動したプロセスが終了してコード 9 を返した後に表示されます。
[parent] before start
[parent] after start: exit code=9
/B は新しいコマンドプロンプトウィンドウを作らずに起動するオプションです。待機を行うのは /WAIT であり、/B ではありません。ほかのオプションが必要な場合は、バッチファイルでの START コマンドの使い方も参照してください。
TIMEOUTとPAUSEは完了待ちではない
TIMEOUT /T 秒数 /NOBREAK は指定時間が経過するまで待ち、PAUSE はキー入力を待ちます。これらは、プログラムが終了したかどうかを確認しません。処理時間が毎回変わるプログラムの完了待ちを、固定秒数の TIMEOUT で置き換えないでください。
Microsoft の TIMEOUT の説明によると、秒数には -1 から 99999 を指定できます。-1 はキーが押されるまで待機し、/NOBREAK は通常のキー入力による中断を無効にします。一定時間の待機そのものが目的なら、バッチファイルで TIMEOUT を使う方法を参照してください。
トラブルシューティング
START /WAITが待つのは、STARTが直接起動したプロセスです。ランチャーが別の切り離された子プロセスへ処理を渡して先に終了するアプリでは、ランチャーを待っても最終処理の完了は保証されません。アプリ固有の完了オプション、終了コード、完了ファイルなどを確認してください。- プロセス名を繰り返し監視する方法を、
START /WAITの一般的な代替にしないでください。同名の別プロセスを誤認するおそれがあります。 - 確認したい終了コードは、対象コマンドの直後に
%ERRORLEVEL%から読み取ります。echo、set、そのほかの後続コマンドによって値が変わることがあります。 - 自動処理の例に
cmd /kを加えないでください。これはコマンドプロンプトを開いたままにするため、スクリプトが完了したかどうかを示す用途には向きません。管理者権限、ユーザー入力、ネットワーク接続、またはアプリ固有の完了通知が必要な場合は、コマンドプロセスを待つだけで十分かをそのアプリのドキュメントで確認してください。
まとめ
通常のコマンドは直接実行します。呼び出し元のバッチへ戻る必要がある別のバッチファイルには CALL を使い、START でプログラムを起動する場合だけ START "" /WAIT を使います。TIMEOUT と PAUSE はバッチファイルを一時停止しますが、プログラムの完了を判定するものではありません。