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


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

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

[code]

    $ find . -name "*.rb" | xargs grep "HogeHoge" | grep "app"
    
[/code]

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




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

[code]

    $ find . -type f -regex ".*app.*\.rb" | xargs grep 'HogeHoge'
    
[/code]

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

追記 0:

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

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

[code]

    $ 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
    
[/code]

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

[code]

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

ちなみに、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
拡張です。

[code]

    $ find . -type f -regex ".*app.*\.rb" -print0 | xargs -0 grep 'HogeHoge'
    
[/code]

余談ですが、`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.

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

[code]

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




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

[code]

    $ find . -type f -regex ".*app.*\.rb" | xargs grep 'HogeHoge'
    
[/code]

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

追記 0:

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

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

[code]

    $ 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
    
[/code]

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

[code]

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

ちなみに、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
拡張です。

[code]

    $ find . -type f -regex ".*app.*\.rb" -print0 | xargs -0 grep 'HogeHoge'
    
[/code]

余談ですが、`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.

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

[code]

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

