バッチファイルが途中で止まったとき、原因はさまざまです。エラーが出て止まるケース、何も表示されず固まるケース、止まっているように見えて実は待機しているだけのケースが混在します。
この記事では、止まる原因を13パターンに分類し、それぞれの見分け方と対処法を解説します。上から順にチェックすれば、最短で原因にたどり着けます。
- 最初にやること:止まっている場所を特定する
- 症状別クイック診断
- 原因1:簡易編集モード(クイック編集)で選択状態になっている
- 原因2:pause / choice / set /p の入力待ち
- 原因3:call なしでバッチファイルを呼んでいる
- 原因4:start /wait で外部プロセスが終了しない
- 原因5:外部コマンドがハングしている
- 原因6:ネットワーク・共有フォルダの応答待ち
- 原因7:ファイルロックで待機している
- 原因8:無限ループで同じ処理を回り続けている
- 原因9:for /f や set /p が標準入力待ちになっている
- 原因10:文字コード・改行コード問題
- 原因11:タスクスケジューラ特有の問題
- 原因12:exit /b の位置ミスでサブルーチンに流れ込む
- 原因13:セキュリティソフト / SmartScreen のブロック
- 止まる問題を最短で解決するチェックリスト
- まとめ
- あわせて読みたい
最初にやること:止まっている場所を特定する
どのパターンに該当するかを切り分ける前に、処理がどこまで進んだかを確定させます。
@echo off setlocal set "LOG=%~dp0run.log" call :main > "%LOG%" 2>&1 exit /b %ERRORLEVEL% :main echo [%time%] === 処理開始 === echo [%time%] STEP1 開始 rem STEP1 の処理 echo [%time%] STEP1 完了 echo [%time%] STEP2 開始 rem STEP2 の処理 echo [%time%] STEP2 完了 echo [%time%] === 処理完了 === exit /b 0
ログに「STEP1 完了」まで出て「STEP2 開始」がなければ、STEP2 の手前で止まっています。
症状別クイック診断
| 症状 | 可能性の高い原因 | 該当セクション |
|---|---|---|
| 画面が固まって何も動かない | 簡易編集モード(選択状態) | 原因1 |
| 「続行するには何かキーを…」で止まる | pause / choice / set /p の残留 | 原因2 |
| 子バッチを呼んだ後の処理が動かない | call なしでバッチを呼んでいる | 原因3 |
| 外部プログラムが終わらない | start /wait で終了待ち / ハング | 原因4・5 |
| ネットワークパスの行で長時間止まる | 共有フォルダの応答待ち | 原因6 |
| ファイル操作の行で止まる | ファイルロック | 原因7 |
| CPU使用率が高いまま終わらない | 無限ループ | 原因8 |
| for /f の行で無言で止まる | 標準入力の継承問題 | 原因9 |
| 先頭行でエラー / 日本語が文字化け | 文字コード・改行コード問題 | 原因10 |
| 手動では動くがスケジュール実行で止まる | タスクスケジューラ特有の問題 | 原因11 |
| 処理が途中で終わる(残りが実行されない) | exit /b 忘れ・サブルーチン設計ミス | 原因12 |
原因1:簡易編集モード(クイック編集)で選択状態になっている
最も見落とされやすく、最も多い原因です。
コマンドプロンプトのウィンドウをマウスでクリックすると、テキストが選択状態(ドラッグ選択)に入り、バッチの処理が一時停止します。タイトルバーに「選択」と表示されます。
対処法(その場):Enter または Esc を押すと解除され、処理が再開します。
対処法(恒久):簡易編集モードを無効にします。
- コマンドプロンプトのタイトルバーを右クリック → プロパティ
- オプション タブ → 「簡易編集モード」のチェックを外す
- OK をクリック
夜間バッチなど無人運行で止まるのは、このケースが非常に多いです。
原因2:pause / choice / set /p の入力待ち
開発時に入れた pause や choice が残っていて、入力待ちで停止しているパターンです。
rem これらのコマンドはすべて入力待ちで止まる pause set /p INPUT=値を入力: choice /c YN /m "続行しますか?"
対処法:
- 自動実行用のバッチからは
pause、set /p、choiceを除去する choiceを使う場合は/tでタイムアウトを設定する- デバッグ用と本番用でバッチを分離する
rem タイムアウト付きの choice(10秒で自動的に Y を選択) choice /c YN /t 10 /d Y /m "続行しますか?"
原因3:call なしでバッチファイルを呼んでいる
バッチファイルから別のバッチファイルを呼ぶとき、call を付けないと呼び出し元に制御が戻りません。
@echo off rem NG: sub.bat の実行後、以降の行は一切実行されない sub.bat echo この行は実行されない
@echo off rem OK: call を付ければ sub.bat 終了後にここに戻る call sub.bat echo sub.bat が終了しました
「バッチが途中で終わる」「残りの処理が動かない」という症状の場合、子バッチの呼び出しに call が付いているか確認してください。
注意:exe の実行には call は不要です。call が必要なのは .bat / .cmd ファイルを呼ぶときだけです。
原因4:start /wait で外部プロセスが終了しない
start /wait はプログラムの終了を待ちますが、プログラムが終了しなければ永遠に待ち続けます。
見分け方:タスクマネージャーで呼び出したプログラムがまだ動いているか確認します。
| 状況 | 原因 | 対処法 |
|---|---|---|
| プロセスが動いている | プログラムが終了していない | 手動で終了する / タイムアウト設計を追加 |
| プロセスがない | ランチャー型で親プロセスだけ終了した | tasklist で本体プロセスを監視する |
| 別のプロセス名で動いている | 自己解凍型・インストーラ型 | msiexec を直接指定する |
rem タイムアウト付きの外部プログラム実行
start "" "C:MyApp ool.exe"
timeout /t 60 /nobreak >nul
tasklist /fi "imagename eq tool.exe" 2>nul | find "tool.exe" >nul
if %ERRORLEVEL% equ 0 (
echo 60秒以内に終了しなかったため強制停止します
taskkill /f /im tool.exe >nul 2>&1
)
原因5:外部コマンドがハングしている
バッチ自体ではなく、呼び出した外部コマンドが応答を返さないケースです。よくある例:
| コマンド | ハングする原因 |
|---|---|
ping |
応答のないホストへの実行(タイムアウトまで待つ) |
nslookup |
DNS サーバーが応答しない |
robocopy |
コピー先のディスク障害・容量不足 |
sqlcmd |
DB サーバーへの接続タイムアウト |
対処法:外部コマンドにはタイムアウトオプションを付けるか、start + tasklist 監視でタイムアウトを自前で実装します。
rem ping には -w(タイムアウトms)と -n(回数)を指定する ping -n 1 -w 3000 192.168.1.1 >nul 2>&1 if %ERRORLEVEL% neq 0 echo サーバーに到達できません
原因6:ネットワーク・共有フォルダの応答待ち
共有フォルダやネットワークドライブへのアクセスが、OS レベルのリトライやタイムアウト待ちで数十秒〜数分止まることがあります。
よくあるパターン:
- マップされたドライブがアイドルで切断された(既定15分)
- 接続先のサーバーが停止・再起動中
- タスクスケジューラ経由ではネットワークドライブがマッピングされていない
対処法:ネットワーク依存の処理の前に事前チェックを入れます。
set "SHARE=\serversharedata"
rem 事前に接続を確立する
net use "%SHARE%" >nul 2>&1
if %ERRORLEVEL% neq 0 (
echo エラー: %SHARE% に接続できません
exit /b 1
)
rem 以降のファイル操作
copy "local.txt" "%SHARE%"
UNC パス(\servershare)を直接指定する方が、ドライブレター(Z:)より安定する場合があります。
原因7:ファイルロックで待機している
別のプロセスがファイルを開いている状態で、そのファイルへの書き込み・削除・移動を行うと、エラーになるか無言で待機します。
ロックの原因になりやすいもの:
- Excel や Word でファイルを開いている
- ウイルス対策ソフトがスキャン中
- Windows のインデックス作成サービス
- 別のバッチが同じファイルにログ出力中
対処法:一時ファイルに出力してからリネームする方式が安全です。
set "TMP_FILE=%~dp0result.tmp" set "OUT_FILE=%~dp0result.csv" rem 一時ファイルに書き出し somecommand > "%TMP_FILE%" rem ロックされにくいタイミングで置換 move /y "%TMP_FILE%" "%OUT_FILE%" >nul
原因8:無限ループで同じ処理を回り続けている
止まっているように見えて、実は同じ箇所を高速で回り続けているケースです。CPU 使用率が高い場合はこれを疑います。
パターン1:遅延変数展開の誤用
if や for のブロック内で %変数% を使うと、ブロック突入時の値で固定されてループを抜けられません。
rem NG: %i% はブロック突入時に展開済みで更新されない set /a i=0 :loop set /a i+=1 if %i% gtr 10 goto done goto loop :done
rem OK: enabledelayedexpansion + !i! で毎回評価される setlocal enabledelayedexpansion set /a i=0 :loop set /a i+=1 if !i! gtr 10 goto done goto loop :done
パターン2:バッチファイル名がコマンド名と衝突
バッチファイルの名前が既存コマンドと同じだと、自分自身を呼び出す無限再帰になります。
rem ファイル名が「find.bat」の場合 rem 以下の find は find.exe ではなく自分自身を呼び出す find "keyword" data.txt
対処法:ping.bat、find.bat、sort.bat、more.bat など、既存コマンドと同じ名前のバッチファイルを作らないでください。
原因9:for /f や set /p が標準入力待ちになっている
for /f や set /p が、リダイレクトやパイプの組み合わせで意図せず標準入力(stdin)を待つ状態になるケースです。
for /f で読むファイルが存在しない
rem NG: ファイルがなくてもエラーにならず、空回りする
for /f "usebackq delims=" %%A in ("%FILE%") do echo %%A
rem OK: 事前に存在確認する
if not exist "%FILE%" (
echo エラー: %FILE% が見つかりません
exit /b 1
)
for /f "usebackq delims=" %%A in ("%FILE%") do echo %%A
set /p がリダイレクト環境で入力待ちになる
set /p をタスクスケジューラや PowerShell から呼んだバッチで使うと、stdin が接続されておらず停止します。自動実行バッチでは set /p を使わない設計にしてください。
for /f 内のパイプでエスケープが必要
rem NG: パイプ | がそのまま解釈されてエラーになる
for /f %%A in ('tasklist | find "cmd.exe"') do echo %%A
rem OK: ^| でエスケープする
for /f %%A in ('tasklist ^| find "cmd.exe"') do echo %%A
原因10:文字コード・改行コード問題
バッチファイルの文字コードや改行コードが正しくないと、コマンドが正しく解釈されず停止・誤動作します。
| 問題 | 症状 | 対処法 |
|---|---|---|
| BOM 付き UTF-8 | 先頭行で「’■’ は…認識されていません」エラー | BOM なしで保存する |
| UTF-8 で日本語を使用 | 日本語が文字化けする | Shift-JIS(ANSI)で保存、または先頭に chcp 65001 |
| 改行コードが LF | コマンドが正しく区切られず異常動作・無限ループ | 改行コードを CRLF に変換する |
最も安全な設定:バッチファイルは Shift-JIS(ANSI)・改行コード CRLF・BOM なし で保存してください。
注意:Git はデフォルトで改行コードを LF に変換します。バッチファイルを Git 管理する場合は .gitattributes で対策します。
rem .gitattributes に追記 *.bat text eol=crlf *.cmd text eol=crlf
原因11:タスクスケジューラ特有の問題
手動実行では動くのに、タスクスケジューラ経由だと止まる・終わらない場合は、以下をチェックします。
| チェック項目 | よくある問題 | 対処法 |
|---|---|---|
| 「開始(オプション)」 | 空のまま → カレントが System32 になる | バッチファイルのフォルダパスを指定 |
| pause / set /p | 入力待ちで永久に停止 | 自動バッチから除去する |
| ネットワークドライブ | タスク実行コンテキストではマップされていない | UNC パスを直接使う / net use で接続 |
| timeout コマンド | 非対話環境で動作しないことがある | ping -n N localhost >nul で代替 |
| 管理者権限 | UAC プロンプトが表示され応答できず停止 | 「最上位の特権で実行する」にチェック |
| 実行時間制限 | タスクが「実行中」のまま終わらない | 「タスクを停止するまでの時間」を設定 |
タスクスケジューラで登録するバッチの先頭には、必ず以下を入れます。
@echo off cd /d "%~dp0"
原因12:exit /b の位置ミスでサブルーチンに流れ込む
call :label でサブルーチンを使っている場合、exit /b を書き忘れると、意図しないラベルに処理が流れ込みます。
rem NG: :main の末尾に exit /b がないため :sub に流れ込む call :main echo 完了 exit /b 0 :main echo メイン処理 rem ← ここに exit /b 0 がない! :sub echo これは呼ばれるはずのないサブルーチン exit /b 0
rem OK: 各ラベルの末尾で必ず exit /b する call :main echo 完了 exit /b 0 :main echo メイン処理 exit /b 0 :sub echo サブルーチン exit /b 0
ルール:すべてのサブルーチンの末尾に exit /b を書くことを徹底してください。
原因13:セキュリティソフト / SmartScreen のブロック
バッチファイルをダブルクリックしたとき、Windows SmartScreen が「WindowsによってPCが保護されました」と表示してブロックすることがあります。
対処法:
- 「詳細情報」→「実行」をクリックする
- ウイルス対策ソフトの除外設定にバッチファイルのフォルダを追加する
- インターネットからダウンロードしたファイルの場合、プロパティの「ブロックの解除」にチェックを入れる
止まる問題を最短で解決するチェックリスト
上から順に確認してください。
- Enter / Esc を押す → 簡易編集モードの選択状態を解除
- ログ出力を追加して止まる行を特定する
- 止まる行に
pause/set /p/choiceがないか確認 - 子バッチの呼び出しに
callが付いているか確認 - タスクマネージャーで外部プロセスが動いているか確認
startの第1引数に空タイトル""があるか確認- ネットワークパスが含まれる行なら接続状態を確認
- CPU 使用率が高ければ無限ループを疑う(遅延変数展開・ファイル名衝突)
- 文字コードが Shift-JIS / 改行が CRLF であるか確認
- タスクスケジューラの場合は「開始(オプション)」が設定されているか確認
まとめ
| 原因 | 見分け方 | 最初の対処 |
|---|---|---|
| 簡易編集モード | タイトルバーに「選択」 | Enter / Esc → プロパティで無効化 |
| 入力待ちコマンド | 「続行するには…」表示 | pause / set /p を除去 |
| call なし | 子バッチ後の処理が動かない | call sub.bat に修正 |
| start /wait | 外部プロセスが終了しない | タイムアウト付き監視に変更 |
| 外部コマンドのハング | 特定コマンドの行で停止 | タイムアウトオプションを付与 |
| ネットワーク待ち | UNC パスの行で長時間停止 | 事前チェック + net use |
| ファイルロック | ファイル操作の行で停止 | 一時ファイル + リネーム方式 |
| 無限ループ | CPU 高負荷、ログが増え続ける | 遅延変数展開 / ファイル名衝突の確認 |
| for /f の stdin 待ち | for /f の行で無言で停止 | ファイル存在確認 / パイプエスケープ |
| 文字コード問題 | 先頭行エラー / 文字化け | Shift-JIS / CRLF / BOM なしで保存 |
| タスクスケジューラ | 手動では動くがスケジュールで止まる | 「開始」設定 + pause 除去 |
| exit /b 忘れ | 別のサブルーチンが実行される | 全ラベル末尾に exit /b を追加 |
| SmartScreen | 「PCが保護されました」 | ブロック解除 / 除外設定 |
