【bat】バッチファイルでファイル存在チェックと条件分岐を実装する完全ガイド|NOT EXIST・AND/OR複合・サイズ0・更新日時・findstr・ループ・実践パターンまで

bat

バッチファイルでファイルの存在を確認して処理を切り替える——これは実務バッチの最も基本的なパターンです。設定ファイルがなければ初期作成する、コピー先が既にあれば上書きをスキップする、ロックファイルが存在すれば二重起動を防ぐ、といった制御がif exist ひとつで実現できます。

本記事では if exist の基本から、AND/OR 複合条件・空ファイル判定・更新日時チェック・ファイル内容検索・ループとの組み合わせまで実践コードで体系的に解説します。

この記事でわかること

  • if exist / if not exist で即時終了する安全な前提チェックパターン
  • ワイルドカードでフォルダ内に特定拡張子のファイルが存在するか確認する
  • ディレクトリ確認と自動 mkdir を組み合わせる定番パターン
  • 複数ファイルがすべて揃っているか(AND)、どれか1つでもあるか(OR)を判定する
  • ファイルサイズが0バイト(空ファイル)かどうかを判定する
  • ファイルの更新日時を使って「今日作成されたファイルか」を判定する
  • ファイルの内容(キーワード)を確認して分岐する
  • for ループと組み合わせて複数ファイルを一括存在確認する
  • ロックファイル・設定ファイル初期化などの実践パターン
スポンサーリンク

ファイル存在チェックのパターン一覧

パターン 構文 用途
存在する場合に処理 if exist “path” ( … ) ファイルがあるときだけ実行
存在しない場合に処理 if not exist “path” ( … ) ファイルがないときだけ実行
存在しなければ即終了 if not exist “path” exit /b 1 前提ファイルの必須チェック
ワイルドカード if exist “dir\*.log” ( … ) 特定拡張子のファイルが1つでもあるか
ディレクトリ確認 if exist “dir\” ( … ) 末尾に \ を付けるとフォルダ判定
AND複合条件 if exist “a” if exist “b” ( … ) 複数ファイルすべて存在する
OR複合条件 フラグ変数 + ループで実装 いずれか1つでも存在する
空ファイル判定 for %%F + if %%~zF equ 0 サイズが0バイト
更新日時チェック for /f + wmic または forfiles 今日/指定日付より新しいか
内容確認 findstr との組み合わせ 特定キーワードを含むか
if exist の基本構文と詳細オプションについて
NOT EXIST・ELSE・NUL を使った基本文法の詳細はIF EXISTでファイル・フォルダの存在確認完全ガイドを参照してください。本記事は実践的な条件分岐パターンに重点を置いて解説します。

if exist / if not exist の安全パターン

最も重要なのは「前提ファイルが存在しなければ処理を即中断する」パターンです。処理の冒頭で前提条件を確認し、不足があれば早期に終了するのが安全なバッチ設計の基本です。

入力ファイル・設定ファイルの必須チェックと即終了
@echo off
setlocal

set "INPUT=C:\data\input.csv"
set "CONFIG=C:\config\app.ini"

REM 前提ファイルが存在しなければエラーコードを変えて即終了
if not exist "%INPUT%" (
    echo [ERROR] 入力ファイルが見つかりません: %INPUT%
    exit /b 1
)

if not exist "%CONFIG%" (
    echo [ERROR] 設定ファイルが見つかりません: %CONFIG%
    exit /b 2
)

echo [OK] ファイル確認完了。処理を開始します
REM 処理本体...
endlocal
設定ファイルが存在しなければデフォルト値で自動作成する
@echo off
setlocal

set "CONFIG=C:\config\app.ini"

REM 親ディレクトリがなければ先に作成する
if not exist "C:\config\" mkdir "C:\config"

if not exist "%CONFIG%" (
    echo 設定ファイルが存在しないため初期ファイルを作成します
    (
        echo [General]
        echo LogLevel=INFO
        echo MaxRetry=3
        echo Timeout=30
    ) > "%CONFIG%"
    echo [OK] 設定ファイルを作成しました: %CONFIG%
) else (
    echo [OK] 設定ファイルを確認しました: %CONFIG%
)

endlocal
終了コードを用途ごとに使い分ける
ファイルごとに終了コードを変える(1, 2, 3…)ことで、呼び出し元バッチや監視ツールがどのファイルが不足していたかを特定できます。エラー処理の設計についてはエラーで処理を中断する方法完全ガイドも参照してください。

ディレクトリの存在確認と自動作成

ログやバックアップの出力先ディレクトリが存在しない場合、コピーや書き込み処理がエラーになります。if not existmkdir を組み合わせて自動作成するのが定番パターンです。

ディレクトリが存在しなければ自動作成する
@echo off
setlocal

set "LOGDIR=C:\logs\batch"
set "BACKUPDIR=D:\backup\daily"

REM ディレクトリ確認には末尾の \ を付けるのが確実
if not exist "%LOGDIR%\" (
    mkdir "%LOGDIR%"
    echo [作成] ログディレクトリを作成しました: %LOGDIR%
)

if not exist "%BACKUPDIR%\" (
    mkdir "%BACKUPDIR%"
    echo [作成] バックアップ先を作成しました: %BACKUPDIR%
)

echo 処理を開始します
endlocal
深い階層のパスを一括作成して ERRORLEVEL で成否を確認する
@echo off

REM cmd の mkdir は中間ディレクトリも含めて一度に作成できる
REM (例: C:\work\2026\03\reports が存在しなくても一発で作成可能)
set "OUTDIR=C:\work\2026\03\reports"

if not exist "%OUTDIR%\" (
    mkdir "%OUTDIR%" 2>nul
    if %ERRORLEVEL% equ 0 (
        echo [OK] ディレクトリ作成: %OUTDIR%
    ) else (
        echo [NG] ディレクトリ作成失敗(権限またはパス不正): %OUTDIR%
        exit /b 1
    )
)
mkdir に /s オプションは存在しない
Windows の mkdir コマンドに /s オプションはありません。ただし mkdir "C:\a\b\c" のように中間ディレクトリを含む深いパスを指定しても、一度に全階層を作成できます(Linux の mkdir -p 相当の動作)。失敗した場合は 2>nul でエラーメッセージを抑制しつつ%ERRORLEVEL% で成否を判断するのが安全です。

ワイルドカードで特定拡張子ファイルの存在を一括確認

フォルダ内に特定拡張子(*.csv*.log)のファイルが1件でもあるかを確認するときにワイルドカードが便利です。ただし if exist "dir\*.csv" は「1件でも存在すれば真」であり、件数の取得はできません。

ワイルドカードで処理対象ファイルの有無を確認してから処理を開始する
@echo off
setlocal

set "INBOX=C:\data\inbox"

REM *.csv が1件でも存在するか確認(存在しなければスキップ)
if not exist "%INBOX%\*.csv" (
    echo [SKIP] 処理対象の CSV ファイルがありません
    exit /b 0
)

echo [OK] CSV ファイルを検出しました。処理を開始します

REM for ループで実際のファイルを1件ずつ処理
for %%F in ("%INBOX%\*.csv") do (
    echo 処理中: %%~nxF
    REM 処理本体...
)

endlocal
複数の拡張子のいずれかが存在するかワイルドカードで確認する
@echo off
setlocal

set "DIR=C:\import"
set "FOUND=0"

REM 複数の拡張子をそれぞれチェック(OR条件の簡易版)
if exist "%DIR%\*.csv" set "FOUND=1"
if exist "%DIR%\*.tsv" set "FOUND=1"
if exist "%DIR%\*.txt" set "FOUND=1"

if "%FOUND%"=="1" (
    echo [OK] インポート対象ファイルを検出
) else (
    echo [SKIP] インポート対象ファイルなし
    exit /b 0
)

endlocal

AND / OR 複合条件でのファイル存在チェック

「複数のファイルがすべて存在する(AND)」か「どれか1つでも存在する(OR)」かを判定するパターンです。

AND条件: 複数ファイルがすべて揃っているか確認する(if ネスト + 不足一覧表示)
@echo off
setlocal

set "FILE_A=C:\data\master.csv"
set "FILE_B=C:\data\transaction.csv"
set "FILE_C=C:\config\rules.ini"

REM 不足ファイルをすべて表示してから終了するパターン
set "MISSING=0"
if not exist "%FILE_A%" ( echo [不足] %FILE_A% & set "MISSING=1" )
if not exist "%FILE_B%" ( echo [不足] %FILE_B% & set "MISSING=1" )
if not exist "%FILE_C%" ( echo [不足] %FILE_C% & set "MISSING=1" )

if "%MISSING%"=="1" (
    echo [ERROR] 必要なファイルが不足しています
    exit /b 1
)

echo [OK] 全ファイル確認完了。処理を開始します
endlocal
AND条件: if をネストしてすべて揃ったときだけ処理する(ネスト版)
@echo off
setlocal

set "FILE_A=C:\data\master.csv"
set "FILE_B=C:\data\transaction.csv"

REM if をネストすることで AND 条件を表現する
if exist "%FILE_A%" (
    if exist "%FILE_B%" (
        echo [OK] 全ファイルあり
        goto :PROCESS
    )
)
echo [ERROR] ファイルが不足しています
exit /b 1

:PROCESS
echo 処理を開始します
endlocal
OR条件: リストのいずれか1つでも存在するか確認する(フラグ変数)
@echo off
setlocal

set "FOUND=0"
set "CONFIG_PATH="

REM 候補パスのうち最初に見つかったものを使用する(OR条件)
for %%F in (
    "C:\app\config.ini"
    "C:\ProgramData\app\config.ini"
) do (
    if "!FOUND!"=="0" (
        if exist %%~F (
            set "FOUND=1"
            set "CONFIG_PATH=%%~F"
        )
    )
)

if "%FOUND%"=="0" (
    echo [ERROR] いずれの場所にも設定ファイルが見つかりません
    exit /b 1
)

echo 使用する設定ファイル: %CONFIG_PATH%
endlocal

AND/OR を使った複合条件の詳細パターンは複数の条件をANDで結合する完全ガイドも参照してください。

ファイルサイズ 0 バイト(空ファイル)の判定

ログファイルの出力が空でないか、CSVにデータ行があるかを確認するにはfor %%F in ("path") do ... %%~zF でサイズを取得して判定します。ループ内でカウンタ変数を使う場合は setlocal enabledelayedexpansion が必要です。

ファイルが空(0バイト)かどうかを判定して処理を分岐する
@echo off
setlocal

set "FILE=C:\data\output.csv"

if not exist "%FILE%" (
    echo [ERROR] ファイルが存在しません
    exit /b 1
)

REM %%~zF でファイルサイズ(バイト数)を取得
for %%F in ("%FILE%") do set "SIZE=%%~zF"

if %SIZE% equ 0 (
    echo [SKIP] ファイルが空です(0バイト): %FILE%
    exit /b 0
) else (
    echo [OK] ファイルサイズ: %SIZE% バイト
    echo 処理を開始します
)

endlocal
フォルダ内の空ファイルを一括検出してログに記録する(setlocal enabledelayedexpansion 使用)
@echo off
setlocal enabledelayedexpansion

set "TARGETDIR=C:\data"
set "LOGFILE=C:\logs\empty_files.txt"
set "COUNT=0"

REM ループ内でカウンタを更新するため enabledelayedexpansion が必要
for %%F in ("%TARGETDIR%\*") do (
    if %%~zF equ 0 (
        echo %%~nxF >> "%LOGFILE%"
        set /a "COUNT+=1"
    )
)

echo 空ファイル数: %COUNT%
if %COUNT% gtr 0 echo 詳細: %LOGFILE%

endlocal
ループ内のカウンタ変数に enabledelayedexpansion が必要な理由
for ループ内で set /a "COUNT+=1" を使う場合、setlocal enabledelayedexpansion がなくても加算自体は動作しますが、ループ内で !COUNT! を参照して分岐したい場合は遅延展開が必須です。習慣として enabledelayedexpansion を付けておくと安全です。ファイルサイズによる多段階判定はファイルサイズを条件分岐に活用する完全ガイドも参照してください。

ファイルの更新日時による条件分岐

「今日作成・更新されたファイルだけ処理する」「指定日数より古いファイルをスキップする」といった日付ベースの条件分岐を実装する方法です。

今日更新されたファイルかどうかを forfiles で判定する
@echo off
setlocal

set "FILE=C:\data\report.csv"

if not exist "%FILE%" (
    echo [ERROR] ファイルが存在しません
    exit /b 1
)

REM forfiles /d 0 = 今日以降に更新されたファイルを対象にする
forfiles /p "C:\data" /m "report.csv" /d 0 >nul 2>&1
if %ERRORLEVEL% equ 0 (
    echo [OK] report.csv は今日更新されています
) else (
    echo [SKIP] report.csv は今日更新されていません
    exit /b 0
)

echo 処理を継続します
endlocal
forfiles でフォルダ内の当日ファイルだけを一括処理する
@echo off
setlocal

set "SRCDIR=C:\data\inbox"

REM /d 0 = 今日以降、/d -1 = 昨日以降、/d -7 = 7日以内
REM 対象ファイルが0件の場合 forfiles はエラーコードを返す
forfiles /p "%SRCDIR%" /m "*.csv" /d 0 /c "cmd /c echo @path" >nul 2>&1
if %ERRORLEVEL% neq 0 (
    echo [SKIP] 本日更新の CSV ファイルがありません
    exit /b 0
)

echo [OK] 本日更新の CSV ファイルを処理します

REM 本日更新分のみを処理
forfiles /p "%SRCDIR%" /m "*.csv" /d 0 /c "cmd /c echo 処理: @file"

endlocal
ファイルの更新日時を変数に取得して日付比較する(wmic 版)
@echo off
setlocal

set "FILE=C:\data\data.csv"

REM 今日の日付を YYYYMMDD 形式で取得
for /f "tokens=2 delims==" %%D in (
    'wmic os get LocalDateTime /value'
) do set "TODAY=%%D"
set "TODAY=%TODAY:~0,8%"

REM ファイルの最終更新日時を YYYYMMDD で取得
for /f "tokens=2 delims==" %%D in (
    'wmic datafile where "name='C:\\data\\data.csv'" get LastModified /value'
) do set "FILEDATE=%%D"
set "FILEDATE=%FILEDATE:~0,8%"

if "%FILEDATE%"=="%TODAY%" (
    echo [OK] ファイルは今日 (%TODAY%) 更新されています
) else (
    echo [SKIP] ファイルの更新日 (%FILEDATE%) が今日 (%TODAY%) と異なります
)

endlocal
forfiles の /d オプションの使い分け
forfiles /d 0 は「今日(当日0時以降)」、/d -1 は「昨日以降」、/d -7 は「7日以内」を意味します。正の数(/d +1)は「明日以降」を指定できます。指定日数より古いファイルを削除する方法は期間以前に更新されたファイルを自動削除する完全ガイドも参照してください。

ファイルの内容(キーワード)を確認して条件分岐する

findstr で特定キーワードを検索し、見つかれば処理を続行・見つからなければスキップ、という「内容ベースの条件分岐」を実装できます。

ファイルに特定キーワードが含まれるか確認して処理を分岐する
@echo off
setlocal

set "LOGFILE=C:\logs\batch.log"

if not exist "%LOGFILE%" (
    echo [SKIP] ログファイルが存在しません
    exit /b 0
)

REM ログに ERROR が含まれるか確認(/i = 大文字小文字を無視)
findstr /i /c:"ERROR" "%LOGFILE%" >nul 2>&1
if %ERRORLEVEL% equ 0 (
    echo [ALERT] ログにエラーを検出しました
    call :NOTIFY_ERROR
) else (
    echo [OK] エラーなし
)

exit /b 0

:NOTIFY_ERROR
echo %DATE% %TIME% エラー検知 >> "C:\logs\alert.log"
goto :eof
設定ファイルの特定キーが有効かどうかを確認してモード切替する
@echo off
setlocal

set "CONFIG=C:\config\app.ini"

if not exist "%CONFIG%" (
    echo [WARN] 設定ファイルなし。デフォルト設定で起動します
    set "LOGLEVEL=INFO"
    goto :START
)

REM DEBUG モードが有効かどうかを設定ファイルで確認
findstr /i /c:"Debug=true" "%CONFIG%" >nul 2>&1
if %ERRORLEVEL% equ 0 (
    echo [DEBUG] デバッグモードで実行します
    set "LOGLEVEL=DEBUG"
) else (
    echo [INFO] 本番モードで実行します
    set "LOGLEVEL=INFO"
)

:START
echo ログレベル: %LOGLEVEL%
endlocal

for ループとの組み合わせで複数ファイルを一括チェックする

処理対象ファイルのリストを事前に確認してから実行することで、途中でエラーになるリスクを下げられます。不足ファイルをすべて列挙してからまとめてエラー終了するパターンも実装できます。

必須ファイルリストを for ループで一括チェックして不足をまとめて報告する
@echo off
setlocal

set "MISSING=0"

REM 必須ファイルのリストを一括チェック
for %%F in (
    "C:\data\master.csv"
    "C:\data\trans.csv"
    "C:\config\app.ini"
    "C:\keys\cert.pem"
) do (
    if not exist %%~F (
        echo [不足] %%~F
        set /a "MISSING+=1"
    ) else (
        echo [OK]   %%~F
    )
)

if %MISSING% gtr 0 (
    echo.
    echo [ERROR] %MISSING% 件のファイルが不足しています。処理を中断します
    exit /b 1
)

echo.
echo [OK] 全ファイルの確認完了。処理を開始します
endlocal
フォルダ内ファイルを走査してコピー先に同名がなければコピーする
@echo off
setlocal

set "SRCDIR=C:\data\inbox"
set "DSTDIR=C:\data\processed"

if not exist "%DSTDIR%\" mkdir "%DSTDIR%"

for %%F in ("%SRCDIR%\*.csv") do (
    REM コピー先に同名ファイルが存在しなければコピー
    if not exist "%DSTDIR%\%%~nxF" (
        copy "%%F" "%DSTDIR%\%%~nxF" >nul
        echo [コピー] %%~nxF
    ) else (
        echo [スキップ] %%~nxF は処理済みです
    )
)

endlocal

ファイル一覧の取得方法についてはフォルダ内ファイル一覧を取得する完全ガイドも参照してください。

実践パターン:存在チェックを組み込んだ実用スクリプト

lock_guard.bat: ロックファイルで二重起動を防止する(タイムスタンプ確認付き)
@echo off
setlocal

set "LOCKFILE=C:\flags\batch_running.lock"
set "LOCK_TIMEOUT_MIN=60"

if not exist "C:\flags\" mkdir "C:\flags"

if exist "%LOCKFILE%" (
    REM ロックファイルが古い(異常終了で残った)場合は強制解除
    forfiles /p "C:\flags" /m "batch_running.lock" /d -0 >nul 2>&1
    if %ERRORLEVEL% equ 0 (
        echo [SKIP] 別のプロセスが実行中です。終了します
        exit /b 0
    ) else (
        echo [WARN] 古いロックファイルを検出。強制解除して続行します
        del "%LOCKFILE%" >nul 2>&1
    )
)

REM ロックファイルを作成
echo %DATE% %TIME% > "%LOCKFILE%"

call :MAIN_PROCESS
set RC=%ERRORLEVEL%

del "%LOCKFILE%" >nul 2>&1
exit /b %RC%

:MAIN_PROCESS
echo 処理を実行中...
timeout /t 3 /nobreak >nul
echo 処理完了
goto :eof
backup_check.bat: バックアップ前後にファイル存在と整合性を確認する
@echo off
setlocal

set "SRC=C:\data"
for /f "tokens=1-3 delims=/" %%A in ("%DATE%") do set "DT=%%A%%B%%C"
set "DEST=D:\backup\%DT%"
set "LOGFILE=C:\logs\backup_%DT%.log"

REM バックアップ元の存在確認
if not exist "%SRC%\" (
    echo [ERROR] バックアップ元が存在しません: %SRC%
    exit /b 1
)

REM バックアップ先を作成
if not exist "%DEST%\" mkdir "%DEST%"

REM バックアップ実行
robocopy "%SRC%" "%DEST%" /e /log:"%LOGFILE%" /np
set RC=%ERRORLEVEL%

REM バックアップ後: ログファイルが生成されているか確認
if not exist "%LOGFILE%" (
    echo [WARN] ログファイルが生成されませんでした
) else (
    for %%F in ("%LOGFILE%") do set "LOGSIZE=%%~zF"
    echo [OK] バックアップ完了: ログサイズ=%LOGSIZE% バイト
)

REM robocopy は 0〜7 が成功、8 以上がエラー
if %RC% geq 8 (
    echo [ERROR] バックアップ失敗: RC=%RC%
    exit /b %RC%
)

endlocal

ファイルコピーの詳細はファイルをコピーする完全ガイド、ファイル削除の安全なパターンはファイルを削除する完全ガイドも参照してください。

よくある落とし穴とトラブルシューティング

症状 原因 対処
ファイルが存在するのに if exist が偽になる 変数展開でスペースを含むパスが分断される "%FILE%" のようにダブルクォートで囲む
ワイルドカードが空フォルダでも真になることがある . や .. などの特殊エントリにマッチしている for ループでフラグ変数を使う確実な方法に切り替える
mkdir でエラー「サブディレクトリまたはファイルは既に存在します」 既存ディレクトリに対して mkdir を実行した if not exist "dir\" で事前確認するか 2>nul でエラーを抑制する
ループ内で set /a のカウンタが増えない 遅延展開なしで !COUNT! を参照している setlocal enabledelayedexpansion を追加して !変数名! で参照する
forfiles で「ファイルが見つかりません」エラー 指定した /m パターンに一致するファイルが0件 if %ERRORLEVEL% neq 0 でファイルなしとして処理を分岐する
wmic で取得した日付が空になる wmic が存在しない環境(Win11 24H2 以降で廃止) PowerShell Get-Date -Format yyyyMMdd に切り替える

まとめ

  • if not exist + exit /b: 前提ファイルの必須チェックは処理冒頭で。ファイルごとに異なる終了コードで不足箇所を特定できる
  • 末尾に \ を付けてディレクトリ判定: if not exist "dir\" + mkdir でフォルダ自動作成が定番パターン。mkdir は中間パスも一度に作成できる
  • ワイルドカード: *.csv で「1件でも存在するか」を一発確認。件数を数えたい場合は for ループを使う
  • AND条件: 不足一覧を全件表示してから exit するパターンが実用的
  • OR条件: フラグ変数をループで設定してループ後に判定
  • サイズ0判定: %%~zF equ 0 で空ファイルを検出。ループ内カウンタには enabledelayedexpansion が必要
  • 更新日時チェック: forfiles /d 0 で今日更新されたファイルのみを対象にできる
  • findstr との組み合わせ: ファイルの内容(キーワードの有無)で分岐できる
  • ロックファイルパターン: 二重起動防止に存在チェックを活用。タイムスタンプで異常終了後の残骸も検出できる

関連記事: IF EXISTでファイル・フォルダの存在確認完全ガイド / ファイルの存在を監視するバッチ完全ガイド / 複数の条件をANDで結合する完全ガイド

よくある質問(FAQ)

Qif exist でフォルダを確認するとき、末尾の \ は必ず必要ですか?
A必須ではありませんが付けることを推奨します。フォルダと同名のファイルが存在する場合の誤判定を防ぐためです。if exist "C:\logs\" とすると logs という名前のディレクトリのみに一致します。末尾 \ なしではファイルとフォルダの両方にマッチするため、厳密な判定が必要な場合は必ず付けてください。
Qワイルドカードで if exist "C:\data\*.csv" としましたが、フォルダが空でも真になることがあります。
A.(カレントディレクトリ)や ..(親ディレクトリ)にマッチしている可能性があります。for %%F in ("C:\data\*.csv") do set "FOUND=1" のようにループでフラグを立てる方法の方が確実です。ループ実行前に set "FOUND=0" でリセットすることを忘れないようにしてください。
Qファイルが存在するのに if exist が偽になることがあります。
A最も多い原因はパスのスペース問題です。set "FILE=%~dp0data file.csv" のようにスペースを含むパスを%FILE% のままダブルクォートなしで if exist に渡すとパスが途中で切断されます。必ず if exist "%FILE%" とダブルクォートで囲んでください。また setlocal enabledelayedexpansion 環境では !FILE! で参照が必要な場合もあります。
Qfor ループでカウンタ変数 COUNT を使っていますが、ループ終了後も 0 のままです。
Aループ内で set /a "COUNT+=1" は実行されていますが、ループブロック内で %COUNT% を参照すると括弧ブロック全体がパース時に展開されるため、ループ開始時の値(0)が表示されます。setlocal enabledelayedexpansion を追加し、ループ内では !COUNT! で参照してください。ループ終了後の参照(if %COUNT% gtr 0)では通常の %変数% で問題ありません。
Qロックファイルを使った二重起動防止でバッチが異常終了したとき、次回起動できなくなりました。
Aforfiles /d -0 でロックファイルの作成が今日かどうかを確認し、古ければ「前回の異常終了で残ったファイル」とみなして強制削除するパターンが有効です。より正確には forfiles /d 0 で「当日更新」かどうかを判定し、当日でなければ古いロックファイルとして削除してから処理を継続します。上記の lock_guard.bat サンプルに実装例を示しています。