結論
@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つの問題点があります。
- forfilesで検索した結果、該当するファイルが見つからない場合に%ERRORLEVEL%が1になる。
- 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コマンドのエラーをキャッチできれば良いので、他の方法でもいけるはずです。
この方の記事が詳しく参考になります。
おまけ:delコマンドでエラーを発生させる
対象ファイルのプロパティを開き、読み取り専用属性を付けてあげるとテストできます。