私はこれを頻繁に使用しました。達成しようとする改善は、grepで一致しなかったエコーファイル名を回避することです。これを行うより良い方法は?
for file in `find . -name "*.py"`; do echo $file; grep something $file; done
find . -name '*.py' -exec grep something {} \; -print
一致する行の後にファイル名を出力します。
find . -name '*.py' -exec grep something /dev/null {} +
一致するすべての行の前にファイル名を出力します(/dev/null
一致するファイルがoneしかない場合grep
は、1つのファイルしか渡されない場合、ファイル名を出力しませんGNU grep
の実装には-H
オプションを使用することもできます)。
find . -name '*.py' -exec grep -l something {} +
少なくとも1つの一致する行があるファイルのファイル名のみを印刷します。
一致する行の前にファイル名beforeを出力するには、代わりにawkを使用できます。
find . -name '*.py' -exec awk '
FNR == 1 {filename_printed = 0}
/something/ {
if (!filename_printed) {
print FILENAME
filename_printed = 1
}
print
}' {} +
または、各ファイルに対してgrep
を2回呼び出します。ただし、ファイルごとに少なくとも1つのgrep
コマンドと最大2つのコマンドを実行するため、効率が低下します(ファイルの内容を2回読み取る) ):
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とその派生物でも動作します)。
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
が必要です。
ファイル名を出力に含めるように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
使用 -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
grep
の選択肢があり、デフォルトで結果を希望の形式で出力します。私が知っている2つの最も人気のあるものは、ag
(別名「銀のサーチャー」)とack
です。 ag
は、ack
のより高速な代替として宣伝されています。
$ ag '^\w+\s*\w+\(' ~/build/i3/src
build/i3/src/display_version.c
58:void display_running_version(void) {
build/i3/src/load_layout.c
42:static TAILQ_HEAD(focus_mappings_head, focus_mapping) focus_mappings =
518:json_content_t json_determine_content(const char *filename) {
575:void tree_append_json(Con *con, const char *filename, char **errormsg) {
build/i3/src/x.c
64:CIRCLEQ_HEAD(state_head, con_state) state_head =
67:CIRCLEQ_HEAD(old_state_head, con_state) old_state_head =
70:TAILQ_HEAD(initial_mapping_head, con_state) initial_mapping_head =
97:void x_con_init(Con *con, uint16_t depth) {
...
ここではお見せできませんが、出力はきれいに色分けされています。ファイル名はオリーブグリーンで、行番号はゴールドイエローで、各行の一致する部分はブラッドレッドで表示されます。色はカスタマイズ可能です。
あなたは次のようなことを試すことができます:
find . -name "*.py:" -exec grep -l {} \;
Findコマンドとその標準のfindコマンド機能によって検出された、すべてのファイルに対するこのexec grepコマンド