假設我有一個patterns.txt
並且想要檢查這些模式中的每一個是否都存在於某個文件中。
我可以做類似的事情:
for pattern in $(cat patterns.txt); do
if ! grep -q "$pattern" file.txt; then
echo "Error: missing pattern $pattern"
fi
done
echo "All patterns found"
但這是低效的,因為它必須重新掃描file.txt
每個模式(如果我們不是在文件中尋找來自可能很大的管道的流中的模式,那麼事情就不那麼簡單了)。
有沒有辦法grep
(或其他工具)檢查是否全部模式存在嗎?
答案1
cat file.txt | awk '
NR == FNR {seen[$0] = 0; next}
{for (p in seen) if ($0 ~ p) seen[p]++}
END {
for (p in seen)
if (seen[p] == 0) {
missing++
print "missing pattern", p
}
if (missing == 0) print "all found"
exit missing
}
' patterns.txt -
將命令替換cat
為任何生成文字的管道。
答案2
這可能效果很好:
sort -u patterns.txt > sorted_patterns.txt # only once
diff -sq <(grep -o -f sorted_patterns.txt file.txt | sort -u) sorted_patterns.txt
如果您有固定字串而不是模式,請使用-F
.這使得grep
速度快很多!
你可以也使用cmp
代替diff -s
。這可能會快一點,但無法顯示缺少的內容。
如果未找到所有模式,則輸出:
Files /dev/fd/63 and /dev/fd/62 differ
或如果已找到所有模式:
Files /dev/fd/63 and /dev/fd/62 are identical
離開-q
才知道什麼不見了。
2a3
> missing_word
答案3
具有grep
PCRE擴展並且還使用printf
命令的力量;你也會做類似的事情:
<infile grep -qzP "(?s)$(printf "(?=.*?%s)" $(<pattern.txt))" &&
echo 'all matched' ||
echo 'one or more pattern(s) does not found'
如果所有模式(在任何訂單) 在輸入檔中找到內菲萊然後發簡訊all matched
將轉到輸出;否則文字one or more pattern(s) does not found
會迴聲。
這會將模式用作匹配模式,例如pat[01]
將匹配pat0
& pat1
;若要符合精確的模式,請從pat[01]
字面上變更printf
控制修飾符,以轉義特殊字元。%s
%q
<infile grep -qzP "(?s)$(printf "(?=.*?%q)" $(<pattern.txt))" &&
echo 'all matched' ||
echo 'one or more pattern(s) does not found'