マッチした行の内容ではなくファイル名だけがほしい

複数のファイルから特定の文字列を検索する際、マッチした行の内容ではなくファイル名だけを知りたい場合がある。

通常のgrepコマンドは、マッチした行の内容を表示する。

$ grep "TODO" *.txt
todo.txt:TODO: レビューを依頼する
notes.txt:TODO: テストケースを追加する

この出力では、どのファイルに検索文字列が含まれるかを確認するのに不要な行内容も表示される。

-l オプションでマッチしたファイル名のみを表示

grepコマンドの-lオプション(--files-with-matches)を使用すると、マッチしたファイル名のみを表示する。

$ grep -l "TODO" *.txt
todo.txt
notes.txt

ファイルに複数のマッチがある場合でも、ファイル名は一度だけ出力される。

$ cat multi.txt
TODO: タスク1
TODO: タスク2
TODO: タスク3

$ grep -l "TODO" multi.txt
multi.txt

-L オプションでマッチしなかったファイル名のみを表示

-Lオプション(--files-without-match)を使用すると、検索文字列にマッチしなかったファイル名のみを表示する。

$ grep -L "TODO" *.txt
memo.txt
done.txt

このオプションは、特定の文字列を含まないファイルを探す際に便利。

ディレクトリ配下を再帰的に検索する

-rオプションと組み合わせてディレクトリ配下を再帰的に検索する。

$ grep -rl "TODO" ./src
./src/main.py
./src/utils/helper.py
./src/tests/test_main.py

-rオプションでディレクトリを再帰的に検索し、-lオプションでファイル名のみを表示する。

xargs と組み合わせて処理する

-lオプションで見つけたファイルをxargsで別のコマンドに渡せる。

$ grep -l "TODO" *.txt | xargs wc -l
  10 todo.txt
  25 notes.txt
  35 total

このコマンドは、TODOを含むファイルの行数をカウントする。

特定の文字列を含むファイルを削除する例。

$ grep -l "deprecated" *.txt | xargs rm

sed と組み合わせて一括置換する

-lオプションで見つけたファイルに対して一括置換を実行する。

$ grep -l "old_function" *.py | xargs sed -i 's/old_function/new_function/g'

このコマンドは、old_functionを含むすべてのPythonファイルで文字列を置換する。

macOSの場合はsed -iに空文字列を指定する必要がある。

$ grep -l "old_function" *.py | xargs sed -i '' 's/old_function/new_function/g'

注意: -lv と -L の違い

-Lオプションと-lv-l-vの組み合わせ)は異なる動作をする。

  • -L: マッチする行が1つもないファイルを表示
  • -lv: マッチしない行が1つでもあるファイルを表示

マッチしない行が1つでもあるファイルを探す場面は稀であるため、通常は-Lオプションを使用する。