文字列のリストがあり、各文字列ごとに大きなソースコードディレクトリに表示されることを確認したいと思います。
私が望むものを提供するGNU grepソリューションを見つけました。
for key in $(cat /tmp/listOfKeys.txt); do
if [ "$(grep -rio -m 1 "$key" . | wc -l)" = "0" ]; then
echo "$key has no occurence";
fi
done
ただし、一致するものを早期に見つけても、常にディレクトリの下のすべてのファイルをgrepするため、非効率的です。検索する必要があるキーも多く、検索する必要があるファイルも多すぎるため、そのまま機能しません。
「標準」Unixツールを使用してこれを効率的に実行する方法を知っていますか?
ベストアンサー1
少なくとも、次のように単純化できます。
set -f # needed if you're using the split+glob operator and don't want the
# glob part
for key in $(cat /tmp/listOfKeys.txt); do
grep -riFqe "$key" . ||
printf '%s\n' "$key has no occurrence"
done
これにより、最初の発生後に検索が停止され、キーが正規表現key
(または可能なオプションgrep
)と見なされなくなります。
ファイルを複数回読み取ることを防ぎ、キーのリストが1行に1つのキーであると仮定するには(上記のコードのように区切られたスペース/タブ/改行の代わりに)GNUツールを使用できます。
find . -type f -size +0 -printf '%p\0' | awk '
ARGIND == 2 {ARGV[ARGC++] = $0; next}
ARGIND == 4 {a[tolower($0)]; n++; next}
{
l = tolower($0)
for (i in a) if (index(l, i)) {
delete a[i]
if (!--n) exit
}
}
END {
for (i in a) print i, "has no occurrence"
}' RS='\0' - RS='\n' /tmp/listOfKeys.txt
key
aが表示されている場合は検索を停止し、すべてのキーが見つかったら停止し、ファイルを一度だけ読むように最適化されています。
キーがにあるとしますlistOfKeys.txt
。キーは小文字で出力されます。
上記のGNUismは、NULで区切られたレコードを処理する機能-printf '%p\0'
と同じです。最初の2つの問題は、次のように解決できます。ARGIND
awk
find . -type f -size +0 -exec printf '%s\0' {} + | awk '
step == 1 {ARGV[ARGC++] = $0; next}
step == 2 {a[tolower($0)]; n++; next}
{
l = tolower($0)
for (i in a) if (index(l, i)) {
delete a[i]
if (!--n) exit
}
}
END {
for (i in a) print i, "has no occurrence"
}' step=1 RS='\0' - step=2 RS='\n' /tmp/listOfKeys.txt step=3
3番目の問題も同様のトリックを使用して解決できます。これしかし、おそらく努力する価値はないでしょう。バラより裸足IOソリューション問題を完全に迂回する方法を探しています。