カレントディレクトリから再帰的に下位の全てのディレクトリをたどって、検索したいことがないだろうか。

これって、ぼくは頻繁に使いたくなるのだが、なぜか解説しているサイトがほとんど見つからなかった。

Grep で特定の拡張子のファイルのみ対象・除外する」の説明を見て、

$ grep -r 検索パターン --include='*.foo'

とすると、拡張子 "foo" のファイルのみ検索対象として、パターンを検索できるのが分かった。

それでも普段ついつい、

$ grep -r 検索パターン *.foo

としてしまう。

他のコマンドでは、指定ファイルのみ対象にしたいとき、このように指定するからだ。

例えば ls の場合、

$ ls *.c

とすると、拡張子が ".c" のファイルのみの一覧を返してくれるのだ。

どうしてこの形式で統一して、 grep でも指定拡張子のみからの検索ができるようにならないのだろう。面倒だ。

・・・と思ったのだが、多分これって、上の "*.c" という指定の結果が展開されるのが、「指定した1つのディレクトリのファイルだけ」だからではないか。

つまり、動作としては、シェル上でコマンドを入力し、その中に、ワイルドカードを使ったファイル名の指定があった場合、そのパターンにマッチするファイル名がシェルによって全て展開され、コマンドに渡される。ただし、当然だが、それは指定した1つのディレクトリのみが対象であり、複数のディレクトリを1つのワイルドカードで指定する方法はない、と。

例えば、 grep -r "foo" ~/bar/baz/*.sh は、 ~/bar/baz/ ディレクトリにある "*.sh" というパターンにマッチするファイルを対象として検索してくれる。ただし、 -r を指定していることの意味はなくなってしまい、 ~/bar/baz/ の下にディレクトリがあっても、それらは検索対象とならない。なぜなら、シェルが ~/bar/baz/*.sh を展開しファイルの一覧をコマンドに渡す結果、対象がそのファイルのあるディレクトリのみに限定されてしまうからだ。

また、 grep -r "foo" ~/bar/*/*.sh などとしてみても、それは ~/bar/ とその下の全てのディレクトリを対象とする、という意味にはならない。

ここまで検証してみて思ったのだが、 find コマンドの場合、

$ find /home/ -name "*.c"

のようにしてやると、指定のディレクトリ /home/ とその下の全てのディレクトリを対象として、 "*.c" というパターンにマッチするファイル名を全て検索してくれる。

grep の場合も、同様に第1オプションで検索を開始するディレクトリを指定するという方法であれば、現在の「 -r 指定により下位のディレクトリも検索できるが、『カレントディレクトリから下位』としか指定できない」という問題も解決できるのだが、どうだろうか。

他の方法としては、

$ sudo cat `sudo find /home/ -name *.c` | grep "foo"

のようにすることで、指定のディレクトリ以下にある指定の拡張子のファイルのみを対象として grep で検索ができる。

さらに他の方法として、

コマンド find ファイル名・タイムスタンプ・ファイルサイズなどを元に、ファイル・ディレクトリを検索する。」によると、

$ grep "foo" `find /home/ -name "*.c"`

のようにすることでも、指定のディレクトリ以下にある指定の拡張子のファイルのみを対象として grep で検索ができる。