いくつかのファイルがあり、文字列は含まれていますが、他の文字列は含まれていないファイルを探したいとします。
grepはラインベースなので、このような条件はgrep -q printf file && grep -vq '#include <stdio.h>' file
機能しません。
どうすればいいですか?
(私はDebianを使用しているので、ツールのGNUバージョンへの答えが適しています。)
答え1
grep -vl
パターンに一致する行が1つ以上あるファイル名を報告します。ここでは、パターンに一致する行のないファイルが必要です。 GNU grep
(Debianにある)には、次の-L
オプションがあります。
grep -rlZ printf . | xargs -r0 grep -FL '#include <stdio.h>'
POSIXの場合、grep
以下を無効にできますgrep -q
。
find . -type f -exec grep -q printf {} \; \
! -exec grep -Fq '#include <stdio.h>' {} \; \
-print
grep
各一般ファイルで 1 つまたは 2 つのインスタンスを実行するという意味なので、効率がはるかに低下します。
答え2
スクリプトの代わりに組み合わせてfind
使用してください。bash -c
ファイルパスを取得してfile
変数に保存し、さらに別のコマンドに渡します。まず、grep -q
希望の単語/パターンがあることを確認してください。終了状態を使用して&&
2番目の状態に渡しますgrep -q
。コマンドが一致するものが見つからないと文字列が見つからないため、終了ステータスを使用してそれをecho
via||
演算子に渡します。
以下の例では、単語のみがfile2.txt
含まれており、abra
含まれていません。cadabra
$ find -type f -exec bash -c 'file="$@";grep -q "abra" "$file" && grep -q "cadabra" "$file" || echo "$file" ' sh "{}" >
./file2.txt
$ ls
file1.txt file2.txt file 3.txt
$ cat file1.txt
abra cadabra
$ cat file2.txt
abra
$ cat file\ 3.txt
abra cadabra
答え3
これはとても簡単です。
for fname in ./*.c; do
if grep -q -F "printf" "$fname" && ! grep -q -F "#include <stdio.h>" "$fname"; then
printf 'File "%s" needs to include stdio.h\n' "$fname"
fi
done
その後、現在のディレクトリ内のすべてのCソースファイルを調べ、ヘッダーを使用しているがprintf()
含まれていないすべてのファイルを報告しますstdio.h
。
ただし、ヘッダーを間接的に含めることができるため、誤検出を防ぐためにできるコードをCプリプロセッサに渡し、前処理された出力でヘッダを見つけます(これはおよびgcc
で動作するようですclang
)。
for fname in ./*.c; do
if grep -q -F "printf" "$fname" && cc -E "$fname" | ! grep -q "^#.*stdio\.h\""; then
printf 'File "%s" needs to include stdio.h\n' "$fname"
fi
done
答え4
要件を正しく読み取るには、すべてのファイル一致から$PAT_INCL
ファイル一致を引いた値が必要です$PAT_EXCL
。
概念的には、これは集合減算にすぎません。 Unixには、セット操作のための非常に良い標準ユーティリティはありませんが、comm
使用できます。
comm -23 <(grep --files-with-match "$PAT_INCL" * | sort) \
<(grep --files-with-match "$PATH_EXCL" * | sort)
2番目のgrepで一致するファイルのみを見つけると、効率が向上する可能性があります。
# Assuming filenames without whitespace
grep --files-with-match "$PAT_INCL" * | sort > incl_files
grep --files-with-match "$PAT_EXCL" $(cat incl_files) | sort > excl_files
comm -23 incl_files excl_files