今回も前回に続きWindowsでの検索コマンドです。今回使うのはforfilesです。こんなコマンドはMS-DOS時代にはありませんでした。では、いつ搭載されたのかとWikiで調べるとWindoss 98〜2000まではリソースキットでの提供、Windows VISTA以降では標準でも使えるようです。今はWindows 7〜11までの環境がほとんどでしょうから、forfilesを使っても問題ないでしょうし、使えるコマンドは積極的に使いましょう。

Wikipediaのforfilesコマンドの解説(英文)
https://en.wikipedia.org/wiki/Forfiles

今回も前回のようにサンプルで利用するファイル・ディレクトリはデスクトップのsampleディレクトリ内に入っています。以後の説明ではカレントディレクトリはsampleディレクトリとしています。コマンドならcd ¥Users¥ユーザー名¥Desktop¥sampleです。ユーザー名部分は使用しているユーザー名を指定してください。すでにコマンドプロンプト起動時に自分のホームフォルダにいる場合はcd Desktop¥sampleと入力しても構いません。

また、forfilesのリファレンスは以下のマイクロソフトの公式ページに用意されています。まずは一読しておくとよいでしょう。

マイクロソフトの公式ページのforfilesのリファレンス
https://docs.microsoft.com/ja-jp/windows-server/administration/windows-commands/forfiles

ツリー表示

 それでは早速forfilesコマンドの説明を、といきたいところですが、その前に視覚的に便利なtreeコマンドを使ってみましょう。
 カレントディレクトリで何もオプションを指定せずにtreeとだけ入力すると以下のようなディレクトリ階層が表示されます。

tree

 さすがにディレクトリだけでは、どのようなファイルがあるのか把握できません。ファイルも表示する場合は/fを指定します。

tree /f

treeコマンドのオプションは他に/aがありますが、ツリー表示に使われる罫線を文字で示すだけです。

tree /f /a

特定の文字が含まれるファイル名だけピックアップしたい場合はfindコマンドと併用することもできます。findの後に指定している/iは英大文字小文字を区別しないというオプションです。区別したい場合は、このオプションを指定する必要はありません。

tree /f | find /i "jpg"

ただし、ディレクトリパスが表示されるわけでもないので、以下のようにリダイレクトを使ってテキストファイルに保存する方が後々使いやすいでしょう。

tree /f > list.txt

ここまではカレントディレクトリが対象でしたが、treeコマンドは対象とするディレクトリ・ドライブを指定することもできます。USBメモリやSDカード内にあるデータを把握するには便利でしょう。
以下のようにするとCドライブのディレクトリツリーが表示されます。/fを指定すればファイルも表示されます。なお、途中で表示を停止させたい場合はcontrolキーを押したままcキーを押してください。

tree c:¥

上記のようにすると表示が早すぎて内容を把握することは困難です。かといってファイルに保存するまでもない場合はパイプとmoreコマンドを組み合わせる方法があります。以下のようにすると画面の縦幅まで表示したらキー入力待ちになります。ページ単位で進めたい場合はスペースキーを押してください。一行ずつ進めたい場合はリターンキー/エンターキーを押してください。Qキーで終了しない場合はcontrolキーを押したままcキーを押すと強制的に表示が中断されます。

tree c:¥ | more

forfilesで検索

 それではforfilesを使って検索してみましょう。まずはカレントディレクトリ内にあるファイルを検索してみます。以下のように何もオプションを指定せずにコマンドを入力します。

forfiles 

サブディレクトリまで検索する場合は/Sを指定します。

forfiles /S

拡張子がtxtのテキストファイルを検索する場合は/Mの後にマスクする文字(ワイルドカード可)を指定します。以下のようにするとカレントディレクトリ内、サブディレクトリ内にあるすべてのテキストファイルを検索します。

forfiles /S /M *.txt

forfilesがUNIX系のfindコマンドに近いのは検索されたファイルに対して、それぞれに処理を行う事ができるからです。検索対象となったファイルに対して処理を行うには/Cオプションを指定します。/Cの後に実行するコマンドを"で囲んで指定します。
以下のようにするとカレントディレクトリだけにあるテキストファイルのサイズが表示されます。

forfiles /M *.txt /C "cmd /c echo @fsize"

/Sを指定すればサブディレクトリ内のテキストファイルまで処理対象になります。

forfiles /S /M *.txt /C "cmd /c echo @fsize"    

ファイルサイズだけ表示されても、それが一体どのファイルなのかわかりません。このような場合、ファイル名も同時に表示したいところです。先程コマンド指定で@sizeという文字列がありましたが、これ以外にも以下のような指定ができます。なお@の後の文字列は大文字でも小文字でも同様に処理されます。

@file拡張子付きのファイル名
@fname拡張子なしのファイル名
@ext拡張子
@pathファイルの完全なパス
@relpathファイルの相対パス
@isdirディレクトリかどうか。ディレクトリならTRUE、そうでなけれぱFALSE
@fsizeファイルサイズ。バイト単位
@fdateファイルの最終更新日
@ftimeファイルの最終更新時刻

ファイル名とファイルサイズを同時に表示するには以下のように指定します。

forfiles /S /M *.txt /C "cmd /c echo @file @fsize"

上記の場合、ファイル名が同じものがあります。すると、どこにあるファイルなのかわかりにくくなります。こんな時にはファイルのパスも同時に表示した方がよいでしょう。パス付きでファイル名とサイズを表示する場合は以下のようになります。

forfiles /S /M *.txt /C "cmd /c echo @path @fsize"

ファイルサイズも数値だけでは分かりにくいので数字の後に単位をつけておきましょう。

forfiles /S /M *.txt /C "cmd /c echo @path @fsize bytes"

typeを使えば対象となったファイルの内容を表示することもできます。以下のようにするとカレントディレクトリにあるtextで始まり、次の1文字が任意の拡張子txtのファイル内容が表示されます。リダイレクトを使えば複数のファイルを連結することもできます。

forfiles /M text?.txt /C "cmd /c type @file"    
forfiles /M text?.txt /C "cmd /c type @file" > all.txt

ファイルサイズで検索

 ファイルサイズを表示できたところで、今度はファイルサイズで検索してみます。
まずは、ファイルサイズが0、つまり空ファイルを検索します。ファイルサイズが0かどうかは条件判断が必要です。条件を調べるにはifを使います。ifの後に条件式を指定します。条件を満たした場合の処理を条件式の後に書きます。
 以下のようにするとカレントディレクトリ内にあるファイルサイズが0のファイルだけが検索され表示されます。

forfiles /S /M *.txt /C "cmd /c if @fsize==0 echo @path"

ifの比較記号は==以外にも以下のものを使用できます。

equ 等しい
neq 等しくない
lss 左辺が右辺より小さい
leq 左辺が右辺より小さいか等しい
gtr 左辺が右辺より大きい
geq 左辺が右辺より大きいか等しい

以下のようにすると6バイトのファイルが表示されます。

forfiles /S /M *.txt /C "cmd /c if @fsize equ 6 echo @path"

6バイト以上の場合は条件式でequを指定している部分をgeqにします。

forfiles /S /M *.txt /C "cmd /c if @fsize geq 6 echo @path"

日付で検索

 forfilesは日付で検索することもできます。と、その前にファイルのタイムスタンプ、更新日を変えておきましょう。ただ、Windowsの場合はPowerShellを使わないとできません。幸にしてマイナビニュースの連載でタイムスタンプの変更方法について書かれた記事があるので参考にしましょう。

・裏技? ファイルの「作成日時」を変更する( Windows 10ミニTips)
https://news.mynavi.jp/article/win10tips-487/
Set-ItemProperty "text1.txt" -name LastWriteTime -Value "2022/04/30 00:00:00"
Set-ItemProperty "text2.txt" -name LastWriteTime -Value "2022/04/29 00:00:00"
Set-ItemProperty "text3.txt" -name LastWriteTime -Value "2022/04/28 00:00:00"

まずカレントディレクトリのファイルの更新日時を表示してみましょう。なお、サブディレクトリは含まないようにしています。

forfiles /c "cmd /c echo @path @fdate @ftime"

更新日が当日の場合は/Dオプションの後に0を指定します。

forfiles /D 0

更新日が1日より前の場合は-1のように負数を指定します。数値を変えると変更された日よりも前のファイル・ディレクトリを検索できます。なお、対象のファイルがない場合はエラーメッセージが表示されます。

forfiles /D -1
forfiles /D -2
forfiles /D -3

指定した日付以降に更新されたファイルを表示する場合は/Dの後に日付または+記号の後に日付を指定します。ここで注意しないといけない点があります。日付の書式が公式ドキュメントとforfiles /?で表示される書式例が異なっています。公式ドキュメント(2022/5/1時点)にはMM/DD/YYYYとありますが、実際に指定するとエラーになってしまいます。forfilesのヘルプでの例のようにYYYY/MM/DDで指定しないといけないようです。

 日付を指定して検索する場合は以下のようになります。この場合、カレントディレクトリ内にある2022年4月29日以降に更新されたファイルが表示されます。

forfiles /D +2022/04/29

負数を指定すると指定した日付よりも前のファイルが検索されます。以下のように指定するとカレントディレクトリ内にある2022年4月29日以前に更新されたファイルが表示されます。

forfiles /D -2022/04/29

古いファイルを削除することもできます。この場合は/Cオプションの後に対象ファイルを削除するDELコマンドを指定します。以下のようにすると2022年4月29日以前に更新されたファイルが削除されます。

forfiles /D -2022/04/29 /C "cmd /c del @file"

forfilesは不要なログファイルなどを削除する場合にも便利です。

あと最後にもう1つ/Pオプションというのがあります。これは検索対象となる基準ディレクトリを指定します。/Pの後に検索対象となるディレクトリパスをします。以下のようにするとCドライブにあるProgram Files (x86)フォルダ以下にあるすべてのテンポラリファイルを検索して表示します。

forfiles /P "C:\Program Files (x86)" /S /M *.tmp

forfilesをうまく使えばちょっとした手間を削減できるでしょう。

著者 仲村次郎
いろいろな事に手を出してみたものの結局身につかず、とりあえず目的の事ができればいいんじゃないかみたいな感じで生きております。