パターンが見つかったファイル名のみを検索してエコーします。

パターンが見つかったファイル名のみを検索してエコーします。

私はこれを大量に使用し、私が達成しようとする改善は、grepで一致しないファイル名がエコーされるのを防ぐことです。これを行うためのより良い方法は何ですか?

    for file in `find . -name "*.py"`; do echo $file; grep something $file; done

答え1

find . -name '*.py' -exec grep something {} \; -print

ファイル名を印刷します後ろに一致する行。

find . -name '*.py' -exec grep something /dev/null {} +

一致する各行の前にファイル名を印刷します(/dev/null私たちが追加した場合は一つ検索するファイルのみを渡す場合、file asと一致するとgrepファイル名は印刷されません。 GNU実装には代替オプションがgrepあります-H

find . -name '*.py' -exec grep -l something {} +

少なくとも1つの一致する行を持つファイルのファイル名のみを印刷します。

ファイル名の印刷今後行を一致させるには、代わりにawkを使用できます。

find . -name '*.py' -exec awk '
  FNR == 1 {filename_printed = 0}
  /something/ {
    if (!filename_printed) {
      print FILENAME
      filename_printed = 1
    }
    print
  }' {} +

または、各ファイルに対して2回呼び出します。各ファイルに対して少なくとも1つのコマンドと最大2つのコマンドをgrep実行し、ファイルの内容を2回読み取ると効率が低下します。grep

find . -name '*.py' -exec grep -l something {} \; \
                    -exec grep something {} \;

いずれにせよ、findそのように出力を繰り返したくありません。そして変数を引用することを忘れないでください

GNU ツールでシェルループを使用するには:

find . -name '*.py' -exec grep -l --null something {} + |
   xargs -r0 sh -c '
     for file do
       printf "%s\n" "$file"
       grep something < "$file"
     done' sh

(FreeBSDおよびその派生物にも適用されます)。

答え2

出力にファイル名を含めるようにgrepに指示できます。したがって、一致するものがあればコンソールに表示されます。ファイルに一致するエントリがない場合、ファイルの行は印刷されません。

find . -name "*.py" | xargs grep -n -H something

からman grep

-H       Always print filename headers with output lines
-n, --line-number
         Each output line is preceded by its relative line number in the file, starting at line 1.  The line number counter is reset for each file processed.
         This option is ignored if -c, -L, -l, or -q is specified.

ファイル名にスペースを含めることができる場合は、NUL文字を区切り文字として使用するようにパイプを切り替える必要があります。これで、完全なコマンドは次のようになります。

find . -name "*.py" -print0 | xargs -0 grep -n -H something

答え3

GNU grepを使用している場合は、その-rオプション--recursiveを使用して次の簡単な検索を実行できます。

grep -r --include '*.py' -le "$regexp" ./ # for filenames only
grep -r --include '*.py' -He "$regexp" ./ # for filenames on each match

findより高度な述部が必要な場合にのみ必要です。

答え4

引数を使用してください-l

for file in `find . -name "*.py"`; do grep -l something $file && grep something $file; done

もっと興味深い使い方は次のとおりです。

for file in $(find . -name '*.py' -exec grep -l something '{}' +); do echo "$file"; grep something $file; done

関連情報