Aqui está um script awk que pesquisa uma string multilinha (as correspondências devem consistir em linhas inteiras). Ele recebe o texto para procurar na variável needle
. O script funciona criando uma janela de w
lines (onde w
é o número de linhas em needle
) e comparando com needle
.
awk -v needle='b 38.\nc 81.\nc 92.\n' '
BEGIN {
if (substr(needle, length(needle)) == "\n")
needle = substr(needle, 1, length(needle)-1);
w = split(needle, needles, "\n");
getline window
for (i = 2; i < w; i++) {getline; window = window "\n" $0}
}
{ window = window "\n" $0 }
window == needle {print NR - w + 1}
{ window = substr(window, index(window, "\n") + 1) }
' <data.txt
Esta não é a maneira mais eficiente de procurar por uma substring, porque cada linha no arquivo de dados é comparada com cada linha no padrão. Existem algoritmos mais eficientes que conseguem realizar menos comparações fazendo algumas pré-computações no padrão, como Knuth-Morris-Pratt .
Para um arquivo que cabe confortavelmente na memória, eu leria tudo de uma vez e executaria a pesquisa na memória. Se tudo o que você está procurando é uma correspondência de padrões, isso é feito facilmente em Perl, mas o Perl não tem primitivas para controlar eficientemente as linhas. Aqui está um script Python que procura por uma string multilinha (que deve ser passada como tal).
import re, sys
needle = sys.argv[1]
haystack = sys.stdin.read()
pos = 0
line = 1
for m in re.finditer(needle, haystack):
line += haystack.count("\n", pos, m.start())
pos = m.start()
print line
Uso: python -c '…' $'b 38.\nc 81.\nc 92.\n' <data.txt