ひぃの雑多書き

日記からお役立ち情報まで色んなことを書きます。

【Windows bat】forfilesを使って実行するdelコマンドのエラーを取得する

結論

@echo off
setlocal enabledelayedexpansion

set file_path=files
forfiles /p %file_path% /S /M *.txt /D -30 /C "cmd /c echo @file"

IF %errorlevel% == 0 (
    FOR /F "usebackq tokens=*" %%i in (`forfiles /p %file_path% /S /M *.txt /D -30 /C "cmd /c echo @path"`) do (
        del /q %%i 2>&1 | find /V ""
        IF !errorlevel! == 0 (
            rem エラー発生
        ) else (
            rem エラーなし
        )
)

やりたいこと

特定のフォルダの中に格納されているファイルの中を検索し、作成日時が30日以上経過しているファイルを削除したい。
また、削除する際にエラーが発生した時にキャッチしたい。

上手くいかない例

set file_path=files
forfiles /p %file_path% /S /M *.txt /D -30 /C "cmd /c del @file"
echo %ERRORLEVEL%

上記のように、forfiles単体でいきなり削除しに行くことも可能です。

しかし、この記述には2つの問題点があります。

  1. forfilesで検索した結果、該当するファイルが見つからない場合に%ERRORLEVEL%が1になる。
  2. delコマンドはファイルの削除に失敗した場合でもERRORLEVELを返さない為、ファイル削除の失敗をキャッチできない

対策1

forfilesを2回に分けて実行する。

1回目のforfilesは『条件に合致するファイルの有無』を確認します。
その為、掲載したソースコードでは"cmd /c echo @file"としているが、ここの内容は何でも良いです。

ERRORLEVELが0の場合、つまり『条件に合致するファイルがあった場合』に削除処理が動くようにします。

対策2

for /fを使い、forfilesで該当ファイルのファイルパスを1行ずつ出力する。
対象ファイルを1つずつ処理できるようになるので、find /V ""を用いてdelコマンドのエラーを検知するようにする。

for文内でERRORLEVELを確認する時は、遅延環境変数を使うのを忘れずに!
また、find /V ""を用いる場合はERRORLEVELが0の場合がエラー、1の場合が正常となります。

for文内に入った後は純粋にdelコマンドのエラーをキャッチできれば良いので、他の方法でもいけるはずです。
この方の記事が詳しく参考になります。

qiita.com

おまけ:delコマンドでエラーを発生させる

対象ファイルのプロパティを開き、読み取り専用属性を付けてあげるとテストできます。