Digamos que eu tenha um patterns.txt
e queira verificar se cada um desses padrões está presente em algum arquivo.
Eu poderia fazer algo como:
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"
mas isso é ineficiente, pois é necessário verificar novamente file.txt
cada padrão (e não é tão simples se, em vez de um arquivo, estivermos procurando padrões em um fluxo proveniente de um canal que pode ser grande, por exemplo).
Existe uma maneira de grep
(ou alguma outra ferramenta) verificar setodosos padrões estão presentes?
Responder1
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 -
Substitua o cat
comando por qualquer pipeline que produza texto.
Responder2
Isso pode funcionar bem:
sort -u patterns.txt > sorted_patterns.txt # only once
diff -sq <(grep -o -f sorted_patterns.txt file.txt | sort -u) sorted_patterns.txt
Se você tiver strings fixas em vez de padrões, use -F
. Isso torna grep
muito mais rápido!
Você poderiatambém usecmp
em vez de diff -s
. Isso pode ser um pouco mais rápido, mas não será capaz de mostrar o que está faltando.
Saída se nem todos os padrões foram encontrados:
Files /dev/fd/63 and /dev/fd/62 differ
ou se todos os padrões foram encontrados:
Files /dev/fd/63 and /dev/fd/62 are identical
Deixe de fora -q
para sabero queestá desaparecido.
2a3
> missing_word
Responder3
com grep
extensão PCRE e também usando poder de printf
comando; você faria algo como:
<infile grep -qzP "(?s)$(printf "(?=.*?%s)" $(<pattern.txt))" &&
echo 'all matched' ||
echo 'one or more pattern(s) does not found'
se todos os padrões (emqualquer ordem) encontrado no arquivo de entradano arquivoentão envie uma mensagemall matched
will vai para a saída; caso contrário, textoone or more pattern(s) does not found
irá ecoar.
isso atuará como padrão como um padrão correspondente, como pat[01]
corresponderá a pat0
& pat1
; para corresponder ao padrão exato, diga pat[01]
literalmente alterar printf
o modificador de controle do %s
qual %q
escapará dos caracteres especiais.
<infile grep -qzP "(?s)$(printf "(?=.*?%q)" $(<pattern.txt))" &&
echo 'all matched' ||
echo 'one or more pattern(s) does not found'