Допустим, у меня есть файл 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'