findとxargsを利用したgrepでマッチしたファイルをパスで絞り込む方法

投稿者: Anonymous

現在、ファイルネームをfindコマンドで絞り込み、パイプでxargs grepして中身を検索したあとに、さらにその出力結果を、パスで絞り込むために、さらにパイプでgrepを繋いでいます。しかし、この方法は同じようなコマンドを二度使っているのでちょっと冗長で、もう少しいい方法がないかと考えています。

具体的には以下のようなコマンドです:

$ find . -name "*.rb" | xargs grep "HogeHoge" | grep "app"

findの使い方がこなれていないのも、上のように冗長になる要因ではあるかとは思いますが、できることならgrepの何らかのオプションで出来る方法があれば教えて下さい。あるいは、この発想自体が筋が悪く、findで対象パスを絞り込むべきならば、その方法を教えてください。

解決

※ すっかり勘違いをしていました。

$ find . -type f -regex ".*app.*.rb" | xargs grep 'HogeHoge'

でしょうか? 念の為、ディレクトリを grep しない様に -type f を find に付けておいた方が良いかと思います。

追記 0:

※ 追記ばかり多くてすみません

-path, -name オプションと GNU find の -regex オプションの違いですが、

$ find . -type f -regex ".*app.*.rb"
  => ./app/a.rb            # Match
  => ./xyz/application.rb  # Match
  => ./application1.rb     # Match
$ find . -type f -path "*app*/*" -name "*.rb"
  => ./app/a.rb            # Match
  => ./xyz/application.rb  # Not match
  => ./application1.rb     # Not match

となります。質問者である esehara さんの目的次第になりますが、-regex オプションではディレクトリ名でもファイル名でも "app" という文字列が含まれているファイル全てにマッチしてしまいます。必要に応じて使い分けると良いかと思います。
なお、-regex オプションのない find コマンドで同じ動作をさせたい場合は、以下の様になります。

$ find . -type f ( -path "*app*/*" -name "*.rb" ) -o -name "*app*.rb"

ちなみに、GNU find には -iregex というオプションがあって、これは大文字か小文字であるかを無視します(case insensitive)。同様に -iname-ilname オプションも用意されています。

追記 その1:

おそらく、-regex は GNU find だけにあるオプションかと思います。

GNU find(1)

-regex pattern

File name matches regular expression pattern. This is a match on the whole path, not a search. For example, to match a file named `./fubar3′, you can use the regular expression `.*bar.’ or `.*b.*3′, but not `f.*r3′. The regular expressions understood by find are by default Emacs Regular Expressions, but this can be changed with the -regextype option.

追記 その2:

fumiyas さんの、

ファイル名に空白などが含まれていても安全です。

について、xargs を使う場合には、find に -print0 と xargs に -0 オプションも付けます。ただし、どちらとも GNU 拡張です。

$ find . -type f -regex ".*app.*.rb" -print0 | xargs -0 grep 'HogeHoge'

余談ですが、zero(NULL) option は GNU tools の幾つかに導入されています。

GNU grep(1)

-z, –null-data

Treat the input as a set of lines, each terminated by a zero byte (the ASCII NUL character) instead of a newline. Like the -Z or –null option, this option can be used with commands like sort -z to process arbitrary file names.

例えば、この -z オプションを使うとテキストファイル全体を単一な論理行とみなして検索を行います。以下は単純なウェブスクレイピングの例です。

$ wget -q -O - http://news.tv-asahi.co.jp/news_politics/articles/000041338.html |
  nkf -w |
  grep --binary-files=text --null-data -Po '(?<=<p>)([sS]+?s*)(?=</p>)'
回答者: user4986

Leave a Reply

Your email address will not be published. Required fields are marked *