コマンド forfiles は、コマンドが 1 日経過していないにもかかわらず、なぜ 1 日経過していないファイルをリストするのでしょうか?

コマンド forfiles は、コマンドが 1 日経過していないにもかかわらず、なぜ 1 日経過していないファイルをリストするのでしょうか?

私が実行しているコマンドはforfiles -p"C:\testdata" -m*.* -d-1 -c"cmd /c echo @PATH\@FILE"

1 日前のファイルのみをリストするように指定しましたが、ステートメントを実行すると、今日作成されたファイルのリストが返されます。

それはなぜでしょうか? 何か間違っているのでしょうか? 日付ではなく、たとえば 24 時間などの期間を指定したほうがよいでしょうか?

私が持っている forfiles のバージョンは次のとおりです。バッチ ファイルは Windows XP で実行されています。FORFILES v 1.1 - [email protected] - 4/98

答え1

Forfiles使用しているバージョンは、ネイティブの XP コマンドではありません。これは、ユーティリティの古いバージョンであり、元々はW2K Resource Kits(確かではありませんが、NT リソース キットにまで含まれていたと思います) 配布されていました。XP でそれを使用すること自体に問題はありませんが、構文をよく見ると、次のように書かれています (強調は筆者による):

-d[+|-][DDMMYY|DD] 日付がDDMMYY以上または以下であるファイルを選択(UTC) または日付が >= または <= (現在の日付 - DD 日) のファイル

注記UTC説明にあります。これは、(1.1) forfilesシステム時間が UTC (オフセットなし)、夏時間でない限り、あなたが考えているのとは異なるタイムスタンプを使用することを意味します。
これはおそらく例を見れば簡単でしょう。私は UTC+1、夏時間です。
(今日の日付 - 2012-09-19)

  • ファイルを作成し、ディレクトリを実行します:

2012-09-19 00:14 5 zzz_utc.txt

今日の日付なので、forfiles によって選択されないはずです。確認してみましょう。

FORFILES -pc:\temp -mzzz_utc.* -d-1 -c"CMD /C Echo @FILE"
zzz_utc.txt

しかし、選択されます。なぜでしょうか? ファイルの UTC 時刻を見てみましょう (PowerShell から次のコマンドを実行します):

ls .\zzz_utc.txt |select LastAccessTime,LastAccessTimeUTC

LastAccessTime                          LastAccessTimeUtc
--------------                          -----------------
2012-09-19 00:15:11                     2012-09-18 22:15:11

ご覧のように、時刻UTC- が使用したものは(1.1) forfiles昨日のものです! そのため、ツールによって選択されます。

答え2

「... 1 日前のファイルのみをリストしたいのですが...」

「昨日作成されたファイル」という意味ですか? つまり、(今日は 9 月 18 日)、変更日時が 9 月 17 日の午前 0000 (早朝の真夜中) 以上、9 月 17 日の末日の真夜中 (深夜) 以下であるファイルです。つまり、日付/時刻の制約が 2 つあり、forfiles1 つ以上を指定することはできません。結論:forfilesそうはならないと思います。

... ただし、Windows 7 ボックスで試してみると/d -1、昨日またはそれ以前に作成されたファイルが表示されます。したがって、Windows XP バージョンがforfiles壊れている可能性があります。

答え3

から優れたドキュメント(強調は筆者による):

最終更新日が現在の日付に指定した日数を加えた日付以降 (+)、または現在の日付以前 (-) のファイルを選択します。指定された日数を引いた値

編集:

おそらく、VBScript を試してみるといいでしょう:

Set args = WScript.Arguments.Named
Set fso  = CreateObject("Scripting.FileSystemObject")

d = 0
p = "."

If args.Exists("?") Or args.Count = 0 Then
  WScript.Echo "Usage: cscript " & WScript.ScriptName & " [/d:DAYS] [/p:PATH]"
  WScript.Quit(0)
End If

If args.Exists("d") Then d = args("d")
If args.Exists("p") Then p = args("p")

refDate = DateAdd("d", d, Now)
TraverseFolders fso.GetFolder(p)

Sub TraverseFolders(fldr)
  For Each f In fldr.Subfolders
    TraverseFolders(f)
  Next
  For Each f In fldr.Files
    If f.DateLastModified < refDate Then
      WScript.StdOut.WriteLine f.Path
      'f.Delete
    End If
  Next
End Sub

答え4

FORFILES /D -1 には Windows 8 および Windows Server 2008 R2 でもバグがあるようです (ギリシャの日付を使用するシステムでは動作しません - すべてのファイルを選択します)

上記のコメントで提案されているように %date% を解析することもできますが、たとえば Windows 8 では日付は最初に曜日名とスペース文字の 3 文字で表示され、その後に従来の日付形式が表示されることに注意してください。また、その日付はローカライズされた形式になりますが、FORFILES /D は forfiles /? に従って dd/MM/yyyy 形式の日付を期待します (少なくとも Win8 では)。

訂正: /D -dd が何をするかについて誤解があるようです (ネットで検索したところ、私だけでなく他の人もそう思っています)。どうやら、dd 日前のファイルではなく、dd 日よりも古いファイルを検索するようです。

したがって、FORFILES の /D +dd/MM/yyyy 構文を使用し、昨日の日付を渡して、昨日以降の日付を持つすべてのファイルを検索する必要があります。これを自動化するには、%date% を使用して、%date:~7,2%/%date:~4,2%/%date:~-4% などで解析します (ロケールに応じて日付部分の順序を変更する必要がある場合があります)。

関連情報