Como posso grep um diretório para linhas que contenham "Foo", mas só recebo correspondências quando a próxima linha também contém "Bar"?
Como posso grep um diretório para linhas que contenham "Foo", mas só recebo correspondências quando a próxima linha também contém "Bar"?
Respostas:
@ warl0ck me apontou na direção certa com pcregrep, mas eu disse "contém", não "é" e perguntei sobre um diretório, não um arquivo.
Isso parece funcionar para mim.
pcregrep -rMi 'Foo(.*)\n(.*)Bar' .
O próprio Grep não parece suportá-lo, use o pcregrep:
Foo
Bar
Foo
abc
pcregrep -M "Foo\nBar" file
Obteve:
Foo
Bar
Fooe Barcompreenderia toda a linha.
Com um sedscript:
#!/bin/sed -nf
/^Foo/{
h # put the matching line in the hold buffer
n # going to nextline
/^Bar/{ # matching pattern in newline
H # add the line to the hold buffer
x # return the entire paragraph into the pattern space
p # print the pattern space
q # quit the script now
}
}
Para usá-lo :
chmod +x script.sed
printf '%s\n' * | ./script.sed
O printfaqui exibe todos os arquivos no diretório atual em uma linha cada e passa-o para sed.
Nota : isso é classificado por ordem alfabética.
Mais informações úteis pattern spacee hold space AQUI .
O grymoire.com tem coisas realmente boas sobre shellprogramação.
h, n, H, x, p, qsignifica? Muito interessante.
pattern space& hold space: grymoire.com/Unix/Sed.html#uh-56 ou em francês commentcamarche.net/faq/9536-sed-introduction-a-sed-part-i
Usando grepapenas, você pode construir o seguinte canal:
grep -A1 'Foo' input_file | grep -B1 'Bar' | grep 'Foo'
O primeiro grepreceberá todas as linhas que contêm Foo, bem como a linha após a partida. Em seguida, obtemos as linhas que contêm Bare a linha antes da partida e, finalmente, extraímos as linhas dessa saída que contém Foo.
EDIT: Como apontou o manatwork , há alguns casos problemáticos a serem observados. Embora seja um desafio interessante, devido à grepfuncionalidade orientada à linha, qualquer solução com ela provavelmente será um "hack" e você provavelmente estará melhor usando algo como o pcregrepque é mais adequado para a tarefa em questão.
find . -name '*.txt' | xargs grep -A1 'Foo' | grep -B1 'Bar'
Embora eu prefira a solução de Nathan usando pcregrep, aqui está a solução usando apenas grep
grep -o -z -P 'Foo(.*)\n(.*)Bar' file
Explicação das opções:
-oimprimir apenas parte correspondente. Necessário, pois a inclusão de -zimprimirá o arquivo inteiro (a menos que haja um \ 0 em algum lugar)-z Trate a entrada como um conjunto de linhas, cada uma terminada por um byte zero (o caractere ASCII NUL) em vez de uma nova linha.-P sintaxe do perl regex EDIT: Esta versão imprime linhas completas correspondentes
grep -o -P -z '(.*)Foo(.*)\n(.*)Bar(.*)' file
-z. Alguns "(. *)" Antes e depois de toda a expressão produziriam todas as linhas correspondentes. Por enquanto, substrings antes de "Foo" e depois de "Bar" não são exibidos.
Com awk:
awk '/bar/ && prev != "" {print FILENAME ": " prev "\n" FILENAME ": " $0}
/foo/ {prev=$0; next}
{prev=""}' file1...
(observação geral sobre a limitação do awk: lembre-se de que, se alguns nomes de arquivos contiverem caracteres "=", será necessário passá-los como em ./filenamevez de filenamepara o awk)