【bat】バッチファイルでエラーログを自動収集する完全ガイド|stderr分離・ERRORLEVEL判定・重大度分類・ログ解析・アラート通知まで

bat

「バッチが失敗しているのに原因がわからない」「エラーメッセージが画面に流れて消えてしまう」——タスクスケジューラで定期実行するバッチほど、エラーログが不可欠です。

しかし単純に >> log.txt でリダイレクトするだけでは、正常な出力とエラーが混在して後から読み解けません。本記事では stderr(エラー出力)だけを分離する方法から始め、ERRORLEVEL判定で失敗コマンドを特定し、重大度ラベル(WARN/ERROR/FATAL)付きの構造化ログを作成する実践パターンを解説します。

この記事でわかること

  • stdout(標準出力)と stderr(エラー出力)を分離してログに保存する方法
  • ERRORLEVEL を判定してエラーが発生したコマンドの情報を記録する方法
  • 重大度(INFO / WARN / ERROR / FATAL)ラベル付きの構造化エラーログを作る方法
  • 複数コマンドのエラーをコマンド名付きで1ファイルに集約する方法
  • findstr・for /f でエラーログを解析してエラー件数を集計する方法
  • エラー発生時に PowerShell でアラート通知を送信する方法
  • 実践パターン:バックアップ処理のエラーログ完全構成
他のログ記事との違い
一般的なログ出力(リダイレクト・タイムスタンプ・ローテーション)はログを出力する方法完全ガイドログを日付別ファイルに自動保存する完全ガイド実行時刻・経過時間をログに記録する完全ガイドを参照してください。この記事はエラーの検出・分類・記録・解析・通知に特化しています。
スポンサーリンク

エラーログ収集手法の比較

手法 検出方式 正常出力との分離 エラー詳細 後解析
2>> error.log stderr自動 コマンド依存
ERRORLEVEL判定 + echo 終了コード ◎(自由記述)
重大度ラベル付き構造化ログ ERRORLEVEL ◎◎ ◎◎
2>&1 で混合保存 stderr自動 △(混在) コマンド依存
2>&1 だけでは不十分な理由
2>&1 は stderr を stdout にマージするため、正常メッセージとエラーメッセージが混在したログになります。後から findstr でエラーを検索できますが、正常出力が多い場合は埋もれがちです。エラーだけを確実に収集するには 2> または 2>> でファイルに直接書き込むか、ERRORLEVEL を判定して明示的に記録する方法を組み合わせましょう。

stderr(エラー出力)を分離してログに保存する

Windowsのコマンドは実行結果をstdout(標準出力:fd=1)stderr(標準エラー出力:fd=2)の2チャンネルに分けて出力します。2> または 2>> でstderrだけをファイルに書き込めます。

2> / 2>> / 2>&1 の使い分け
@echo off

REM -- stderr だけをファイルに上書き保存(毎回クリアされる)
dir Z:\ 2> error.log

REM -- stderr だけをファイルに追記(前回分が残る)
copy C:\test\file.txt D:\backup\ 2>> error.log

REM -- stdout は画面、stderr だけをファイルに保存
xcopy C:\src D:\dst /s 2>> error.log

REM -- stdout と stderr を両方ファイルに保存(混在)
robocopy C:\src D:\dst /E > all.log 2>&1

REM -- stdout と stderr を別々のファイルに保存
robocopy C:\src D:\dst /E > success.log 2> error.log
コマンドによっては stderr を使わないものもある
robocopy は終了コードで成否を表し、エラーメッセージも stdout に出力します。2> で何も捕捉できない場合は、コマンドが stderr を使っていない可能性があります。その場合は後述の ERRORLEVEL 判定でエラーを検出してください。
stderr が空かどうかを確認してエラー有無を判定する
@echo off
setlocal

set "ERRLOG=C:\logs\error.log"

REM エラーログを空ファイルで初期化
type nul > "%ERRLOG%"

xcopy C:\src D:\dst /s 2>> "%ERRLOG%"

REM エラーログのサイズが 0 より大きければエラーあり
for %%F in ("%ERRLOG%") do (
    if %%~zF gtr 0 (
        echo [ERROR] エラーが発生しました。ログ: %ERRLOG%
        exit /b 1
    ) else (
        echo [OK] エラーなし
    )
)
endlocal

ERRORLEVEL を判定してエラー情報を明示的に記録する

ERRORLEVEL(終了コード)はコマンドが正常終了したかどうかを示す数値です。0 が成功、1以上が失敗を意味します(コマンドによって異なる)。コマンド実行直後に判定して、失敗時の詳細情報を自分でログに書き込む方法が最も確実です。

ERRORLEVEL を判定してエラーをログに記録する基本パターン
@echo off
setlocal

set "LOGFILE=C:\logs\batch_%DATE:~0,4%%DATE:~5,2%%DATE:~8,2%.log"

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

REM コマンドを実行
xcopy C:\src\*.csv D:\backup\ /y >nul 2>&1

REM ERRORLEVEL を即座に変数に保存(次のコマンドで上書きされる前に)
set RC=%ERRORLEVEL%

if %RC% neq 0 (
    echo [%DATE% %TIME%] [ERROR] xcopy 失敗 ERRORLEVEL=%RC% >> "%LOGFILE%"
) else (
    echo [%DATE% %TIME%] [INFO]  xcopy 成功 >> "%LOGFILE%"
)

endlocal
ERRORLEVEL の保存は実行直後に行う
if %ERRORLEVEL%set RC=%ERRORLEVEL% はコマンド実行直後の次の行に書く必要があります。echoset など別のコマンドを挟むと上書きされます。また if errorlevel 1(変数展開なし)形式は「1以上」を意味するため、正確な値比較には if %RC% equ 1 を使ってください。
robocopy の終了コード別にログメッセージを変える
@echo off
setlocal

set "LOGFILE=C:\logs\robocopy_%DATE:~0,4%%DATE:~5,2%%DATE:~8,2%.log"

robocopy C:\src D:\dst /E /NFL /NDL /NJH /NJS > nul
set RC=%ERRORLEVEL%

REM robocopy 終了コード: 0=変更なし 1=コピー成功 2=追加ファイルあり
REM                      4=不一致 8=エラー 16=致命的エラー
if %RC% lss 8 (
    echo [%DATE% %TIME%] [INFO]  robocopy 正常終了 RC=%RC% >> "%LOGFILE%"
) else (
    echo [%DATE% %TIME%] [ERROR] robocopy エラー RC=%RC% >> "%LOGFILE%"
    exit /b %RC%
)

endlocal

重大度ラベル付きの構造化エラーログを作成する

エラーログに INFO / WARN / ERROR / FATAL のレベルを付けておくと、後から findstr で重大なエラーだけを抽出できます。日時・処理ステップ名・終了コードを含む構造化フォーマットにしておくと運用保守が格段に楽になります。

重大度ラベル付き構造化ログのフォーマット
@echo off
setlocal enabledelayedexpansion

set "LOGFILE=C:\logs\app_%DATE:~0,4%%DATE:~5,2%%DATE:~8,2%.log"
if not exist "C:\logs\" mkdir "C:\logs"

REM ログ書き込み用のサブルーチンを呼ぶ
call :LOG INFO  "処理開始"

REM ステップ1: バックアップ
robocopy C:\data D:\backup /E /NFL /NDL /NJH /NJS > nul
set RC=%ERRORLEVEL%
if %RC% geq 8 (
    call :LOG ERROR "バックアップ失敗 RC=%RC%"
    call :LOG FATAL "処理中止"
    exit /b 1
) else (
    call :LOG INFO  "バックアップ完了 RC=%RC%"
)

REM ステップ2: 古いファイル削除
forfiles /p C:\data /d -30 /c "cmd /c del @path" 2>nul
set RC=%ERRORLEVEL%
if %RC% neq 0 (
    call :LOG WARN "forfiles 終了コード=%RC%(削除対象なし、または軽微なエラー)"
)

call :LOG INFO  "処理終了"
exit /b 0

:LOG
REM 使い方: call :LOG LEVEL "メッセージ"
set "LVL=%~1"
set "MSG=%~2"
echo [%DATE% %TIME%] [%LVL%] %MSG% >> "%LOGFILE%"
if /i "%LVL%"=="ERROR" echo [%DATE% %TIME%] [ERROR] %MSG%
if /i "%LVL%"=="FATAL" echo [%DATE% %TIME%] [FATAL] %MSG%
exit /b 0

このパターンでは call :LOG サブルーチンに統一することでログフォーマットが一定になります。ERROR/FATAL レベルは画面にも表示し、INFO/WARN はファイルのみに記録します。

ログフォーマットの推奨例
[2026-03-22 09:15:03.42] [ERROR] バックアップ失敗 RC=8
日時・レベル・メッセージの3要素が揃っていると、findstr "[ERROR]" app_20260322.log で即座に問題を絞り込めます。

複数コマンドのエラーをコマンド名付きで1ファイルに集約する

複数の処理ステップを持つバッチでは、どのコマンドでエラーが発生したかをログに明記しておくことが重要です。エラーが発生してもすべての処理を最後まで実行し、まとめて報告するパターンを紹介します。

複数コマンドのエラーをコマンド名付きで集約して最後にサマリーを出す
@echo off
setlocal enabledelayedexpansion

set "LOGFILE=C:\logs\batch_%DATE:~0,4%%DATE:~5,2%%DATE:~8,2%.log"
if not exist "C:\logs\" mkdir "C:\logs"

set "ERRORS=0"
set "ERROR_CMDS="

echo [%DATE% %TIME%] === バッチ処理開始 === >> "%LOGFILE%"

REM --- ステップ1: ファイルコピー ---
xcopy "C:\src\data" "D:\backup\data" /s /y /q >nul 2>> "%LOGFILE%"
set RC=%ERRORLEVEL%
if %RC% neq 0 (
    set /a "ERRORS+=1"
    set "ERROR_CMDS=!ERROR_CMDS! [xcopy RC=%RC%]"
    echo [%DATE% %TIME%] [ERROR] xcopy 失敗 RC=%RC% >> "%LOGFILE%"
) else (
    echo [%DATE% %TIME%] [INFO]  xcopy 完了 >> "%LOGFILE%"
)

REM --- ステップ2: DB エクスポート ---
mysqldump -u root mydb > "D:\backup\mydb.sql" 2>> "%LOGFILE%"
set RC=%ERRORLEVEL%
if %RC% neq 0 (
    set /a "ERRORS+=1"
    set "ERROR_CMDS=!ERROR_CMDS! [mysqldump RC=%RC%]"
    echo [%DATE% %TIME%] [ERROR] mysqldump 失敗 RC=%RC% >> "%LOGFILE%"
) else (
    echo [%DATE% %TIME%] [INFO]  mysqldump 完了 >> "%LOGFILE%"
)

REM --- ステップ3: 古いバックアップ削除 ---
forfiles /p "D:\backup" /d -7 /c "cmd /c del @path" 2>> "%LOGFILE%"
REM forfiles は対象なしのときも 1 を返すので ERRORLEVEL は無視する

REM --- サマリー ---
echo [%DATE% %TIME%] === 処理終了 ERRORS=%ERRORS% === >> "%LOGFILE%"
if %ERRORS% gtr 0 (
    echo [%DATE% %TIME%] [SUMMARY] エラーコマンド:%ERROR_CMDS% >> "%LOGFILE%"
    echo エラーが %ERRORS% 件発生しました:%ERROR_CMDS%
    exit /b 1
) else (
    echo [%DATE% %TIME%] [SUMMARY] すべて正常終了 >> "%LOGFILE%"
    echo 全ステップ正常終了
)

endlocal

エラーログを日付別ファイルに保存してローテーションする

一般ログとエラーログを別ファイルに分け、エラーログは長期保存するパターンが運用に向いています。エラーが発生した日だけファイルが作成されるため、ディスク節約にもなります。

エラーログを日付別ファイルに分けて 90 日以上古いものを削除する
@echo off
setlocal

set "LOGDIR=C:\logs"
set "TODAY=%DATE:~0,4%%DATE:~5,2%%DATE:~8,2%"
set "ERRLOG=%LOGDIR%\error_%TODAY%.log"
set "INFOLOG=%LOGDIR%\info_%TODAY%.log"

if not exist "%LOGDIR%\" mkdir "%LOGDIR%"

REM 処理(stdout=通常ログ / stderr=エラーログ に分離)
robocopy C:\src D:\dst /E /LOG+:"%INFOLOG%" 2>> "%ERRLOG%"
set RC=%ERRORLEVEL%
if %RC% geq 8 (
    echo [%DATE% %TIME%] [ERROR] robocopy RC=%RC% >> "%ERRLOG%"
)

REM 90 日以上古いログを削除(エラーログ・通常ログ両方)
forfiles /p "%LOGDIR%" /m "error_*.log" /d -90 /c "cmd /c del @path" >nul 2>&1
forfiles /p "%LOGDIR%" /m "info_*.log"  /d -90 /c "cmd /c del @path" >nul 2>&1

endlocal

ログのローテーション設計の詳細はログを日付別ファイルに自動保存する完全ガイドも参照してください。

エラーログを解析してエラー件数・重大度を集計する

蓄積されたエラーログを解析し、今日のエラー件数・FATAL の有無・頻発コマンドを集計できます。findstrfor /f を組み合わせて実装します。

今日のエラーログから ERROR/FATAL の件数を集計する
@echo off
setlocal enabledelayedexpansion

set "TODAY=%DATE:~0,4%%DATE:~5,2%%DATE:~8,2%"
set "LOGFILE=C:\logs\app_%TODAY%.log"

if not exist "%LOGFILE%" (
    echo ログファイルが見つかりません: %LOGFILE%
    exit /b 0
)

set "CNT_ERROR=0"
set "CNT_WARN=0"
set "CNT_FATAL=0"

for /f "usebackq delims=" %%L in ("%LOGFILE%") do (
    echo %%L | findstr /c:"[ERROR]" >nul 2>&1 && set /a "CNT_ERROR+=1"
    echo %%L | findstr /c:"[WARN]"  >nul 2>&1 && set /a "CNT_WARN+=1"
    echo %%L | findstr /c:"[FATAL]" >nul 2>&1 && set /a "CNT_FATAL+=1"
)

echo === %TODAY% エラーサマリー ===
echo FATAL : !CNT_FATAL!
echo ERROR : !CNT_ERROR!
echo WARN  : !CNT_WARN!

if !CNT_FATAL! gtr 0 (
    echo [FATAL あり] 至急確認してください: %LOGFILE%
    exit /b 2
) else if !CNT_ERROR! gtr 0 (
    exit /b 1
) else (
    exit /b 0
)

endlocal
エラーログから特定パターンの行だけを抽出して別ファイルに保存する
@echo off
setlocal

set "LOGDIR=C:\logs"
set "TODAY=%DATE:~0,4%%DATE:~5,2%%DATE:~8,2%"

REM ERROR または FATAL を含む行だけを抽出
findstr /i /c:"[ERROR]" /c:"[FATAL]" "%LOGDIR%\app_%TODAY%.log" > "%LOGDIR%\critical_%TODAY%.log" 2>nul

REM 抽出されたファイルが空でなければ報告
for %%F in ("%LOGDIR%\critical_%TODAY%.log") do (
    if %%~zF gtr 0 (
        echo [重大エラーあり] %%~zF bytes >> "%LOGDIR%\summary_%TODAY%.txt"
        type "%LOGDIR%\critical_%TODAY%.log"
    )
)

endlocal

エラー発生時に PowerShell でアラート通知を送信する

エラーログにFATAL/ERRORが記録されたタイミングで、PowerShell から通知メールや Slack Webhook を呼び出すことで無人運用の監視体制を構築できます。

エラー発生時に PowerShell でメール通知を送信する
@echo off
setlocal

set "LOGFILE=C:\logs\app_%DATE:~0,4%%DATE:~5,2%%DATE:~8,2%.log"
set "MAIL_TO=admin@example.com"
set "SMTP=smtp.example.com"

REM 処理実行
call :RUN_BACKUP
set RC=%ERRORLEVEL%

if %RC% neq 0 (
    echo [%DATE% %TIME%] [FATAL] バックアップ失敗 RC=%RC% >> "%LOGFILE%"

    REM PowerShell でメール通知
    powershell -NoProfile -Command ^
        "Send-MailMessage -To '%MAIL_TO%' -From 'batch@example.com' ^
         -Subject '[ALERT] バッチエラー %DATE%' ^
         -Body (Get-Content '%LOGFILE%' -Raw) ^
         -SmtpServer '%SMTP%'"
)

exit /b %RC%

:RUN_BACKUP
robocopy C:\src D:\dst /E /NFL /NDL >nul
if %ERRORLEVEL% geq 8 exit /b %ERRORLEVEL%
exit /b 0
Slack Webhook にエラーメッセージを POST する
@echo off
setlocal

set "WEBHOOK_URL=https://hooks.slack.com/services/XXX/YYY/ZZZ"
set "CHANNEL=#alerts"
set "MSG=[ALERT] バッチエラー発生 %DATE% %TIME%"

REM PowerShell で Slack Webhook に POST
powershell -NoProfile -Command ^
    "$body = ConvertTo-Json @{text='%MSG%'; channel='%CHANNEL%'}; ^
     Invoke-RestMethod -Uri '%WEBHOOK_URL%' ^
         -Method Post -Body $body -ContentType 'application/json'"

endlocal

メール・Slack・Blat などの通知手段の詳細はエラー通知メールを自動送信する完全ガイドも参照してください。

実践パターン:バックアップ処理のエラーログ完全構成

ここまで解説した技術をすべて組み合わせた、実運用に耐えるバックアップバッチのエラーログ完全構成です。

バックアップ処理のエラーログ完全構成(構造化ログ + 解析 + 通知)
@echo off
setlocal enabledelayedexpansion

REM ===== 設定 =====
set "SRC=C:\data"
set "DST=D:\backup"
set "LOGDIR=C:\logs\backup"
set "TODAY=%DATE:~0,4%%DATE:~5,2%%DATE:~8,2%"
set "LOGFILE=%LOGDIR%\backup_%TODAY%.log"
set "ERRFILE=%LOGDIR%\error_%TODAY%.log"
set "MAIL_TO=admin@example.com"

if not exist "%LOGDIR%\" mkdir "%LOGDIR%"

REM ===== ログ初期化 =====
set "ERRORS=0"
call :LOG INFO  "======== バックアップ開始 ========"
call :LOG INFO  "SRC=%SRC%  DST=%DST%"

REM ===== ステップ1: robocopy バックアップ =====
robocopy "%SRC%" "%DST%" /E /XD ".git" "node_modules" ^
    /LOG+:"%LOGFILE%" /NJH /NJS /NFL /NDL 2>> "%ERRFILE%"
set RC=%ERRORLEVEL%
if %RC% geq 8 (
    call :LOG ERROR "robocopy 失敗 RC=%RC%"
    set /a "ERRORS+=1"
) else (
    call :LOG INFO  "robocopy 完了 RC=%RC%"
)

REM ===== ステップ2: 90日以上古いバックアップを削除 =====
forfiles /p "%DST%" /d -90 /c "cmd /c if @isdir==FALSE del @path" >nul 2>> "%ERRFILE%"
set RC=%ERRORLEVEL%
if %RC% neq 0 (
    call :LOG WARN  "forfiles 終了コード=%RC%(削除対象なしの可能性あり)"
)

REM ===== サマリー =====
call :LOG INFO  "======== バックアップ終了 ERRORS=!ERRORS! ========"

if !ERRORS! gtr 0 (
    REM エラーログをメール通知
    powershell -NoProfile -Command ^
        "Send-MailMessage -To '%MAIL_TO%' -From 'batch@srv' ^
         -Subject '[ERROR] バックアップ失敗 %TODAY%' ^
         -Body (Get-Content '%ERRFILE%' -Raw -ErrorAction SilentlyContinue) ^
         -SmtpServer 'smtp.example.com'" >nul 2>&1
    exit /b 1
) else (
    REM エラーログが空なら削除してディスクを節約
    for %%F in ("%ERRFILE%") do if %%~zF equ 0 del "%%F" >nul 2>&1
    exit /b 0
)

:LOG
set "LVL=%~1"
set "MSG=%~2"
echo [%DATE% %TIME%] [%LVL%] %MSG% >> "%LOGFILE%"
if /i "!LVL!"=="ERROR" echo [%DATE% %TIME%] [ERROR] %MSG%
if /i "!LVL!"=="FATAL" echo [%DATE% %TIME%] [FATAL] %MSG%
exit /b 0

並列処理でのログ管理はバッチファイルで並列処理を実行する方法、自動デプロイでのエラーハンドリングはバッチファイルで自動デプロイを実現する完全ガイドも参照してください。

エラーログ収集のトラブルシューティング

症状 原因 対処法
2>> でログが空になる コマンドが stderr を使わない(robocopy など) ERRORLEVEL 判定で手動記録する
ログに文字化けが出る コマンドプロンプトのコードページ(CP932)とログの不一致 バッチ先頭に chcp 65001 >nul でUTF-8に統一
ERRORLEVEL が常に 0 になる コマンドが終了コードを設定しない stderr ファイルのサイズで判定する方法を使う
forfiles がエラーコード 1 を返す 削除対象ファイルが存在しない(正常) forfiles の終了コードは無視し stderr のみ確認する
ループ内のカウンタが増えない enabledelayedexpansion なし setlocal enabledelayedexpansion を追加し !VAR! で参照する
ログファイルが日付ごとに増えすぎる ローテーション未設定 forfiles /d -N で古いログを定期削除する

まとめ

  • 2>> error.log: stderr だけをエラーログに分離保存。正常出力との混在を防ぐ基本
  • ERRORLEVEL 即時保存: set RC=%ERRORLEVEL% をコマンド実行直後に記述。別コマンドで上書きされる前に確保する
  • 重大度ラベル付き構造化ログ: call :LOG ERROR "メッセージ" パターンで INFO / WARN / ERROR / FATAL を統一フォーマットで記録
  • コマンド名付きエラー集約: エラー発生コマンド名を変数に蓄積してサマリー出力。どのステップで失敗したか即特定
  • エラーログ解析: findstr /c:"[ERROR]"for /f でエラー件数を集計。FATAL があれば即アラート
  • アラート通知: エラー時のみ PowerShell Send-MailMessage / Slack Webhook で通知。正常時は通知ゼロで運用負担を減らす
  • エラーログが空なら削除: エラーのなかった日のファイルを削除するとエラー発生日がひと目でわかる

関連記事: ログを出力する方法完全ガイド / ログを日付別ファイルに自動保存する完全ガイド / 実行時刻・経過時間をログに記録する完全ガイド / エラー通知メールを自動送信する完全ガイド

よくある質問(FAQ)

Q2>> error.log で保存しているのにファイルが空です。
Aコマンドによっては stderr(fd=2)を使わずに stdout(fd=1)にすべて出力するものがあります。robocopydirecho などが代表例です。その場合は ERRORLEVEL を判定して手動でログに書き込む方法を使ってください。stderr を使うかどうかは コマンド 2>test.log && echo stdout のように実際に試して確認するのが確実です。
Qタスクスケジューラで実行するとログが残らないことがあります。
Aタスクスケジューラで実行すると作業ディレクトリが変わり、相対パスのログファイルが意図しない場所に作成されることがあります。ログファイルのパスは必ず絶対パスで指定してください。また %DATE% の書式もロケール依存があるため、wmic os get LocalDateTime を使う方法が安全です。詳細はログを日付別ファイルに自動保存する完全ガイドを参照してください。
Qログにエラーメッセージが日本語で書かれているが文字化けしています。
AコマンドプロンプトのデフォルトはCP932(Shift-JIS)です。ログファイルをUTF-8で読もうとすると文字化けします。バッチ先頭に chcp 65001 >nul を追加してUTF-8に変更するか、ログファイルをShift-JIS対応のエディタ(メモ帳など)で開いてください。ただし chcp 65001 に変更すると一部の日本語環境コマンドが正常動作しなくなる場合があるため、動作確認を行ってから適用してください。
Qif %ERRORLEVEL% neq 0 で判定しているのに、エラーなのに 0 と判定されます。
A2つの原因が考えられます。①%ERRORLEVEL% の参照前に別のコマンドが実行されて上書きされた(直後の setecho でも書き換わる)。コマンド実行直後に set RC=%ERRORLEVEL% で変数に退避してください。② コマンド自体が失敗しても終了コード 0 を返す仕様の場合。その場合は stderr のファイルサイズで判定する方法を使ってください。
Qログファイルが大量に溜まってディスクを圧迫しています。整理する方法を教えてください。
Aforfiles /p "C:\logs" /m "error_*.log" /d -90 /c "cmd /c del @path" で90日以上前のエラーログを自動削除できます。タスクスケジューラで月1回実行するように設定しておくと管理が楽です。エラーが発生しなかった日のログが0バイトになる場合は、for %%F in (C:\logs\error_*.log) do if %%~zF equ 0 del "%%F"で空ファイルをまとめて削除できます。ローテーション設計の詳細はログを出力する方法完全ガイドを参照してください。