Se eu entendi corretamente, você só quer linhas contendo X se elas forem seguidas por uma linha contendo Y, e então você quer as duas linhas.
grep -A1 X filename |grep --no-group-separator -B1 Y
Ainda lutando com arquivos de log confusos. O que eu quero é encontrar linhas que coincidam primeiro com a string X e depois com a string Y. Eu então quero imprimi-las juntas. O problema é que, às vezes, há X, mas não Y.
Exemplo de entrada
31 X
32 Y
33 X
34 Y
35 X
36 X
37 Y
38 X
39 X
Saída esperada
31 X
32 Y
33 X
34 Y
36 X
37 Y
Assim, as linhas 35, 38 e 39 são omitidas porque não há nenhuma string Y.
Meu ponto de partida é o seguinte:
cat $filename | grep -E X\|Y | grep -A1 'X'
Mas isso não filtra as linhas 35, 38 e 39. O que eu quero é uma condição: apenas imprima as linhas X e Y se houver Y. Se não, não imprima nada.
Usando sed
:
sed -n ':b /X/ { h; n; /Y/! b b; H; x; p; }'
Saída:
31 X
32 Y
33 X
34 Y
36 X
37 Y
Outro sed
:
$ sed -e '/X/{
$!N
/\n.*Y/!D
}' file
31 X
32 Y
33 X
34 Y
36 X
37 Y
Existem várias ferramentas que podem fazer isso. Se você tem pcregrep
(deve estar disponível no repositório de sua distribuição), você pode fazer:
$ pcregrep -M 'X\n[^\n]+Y' file
31 X
32 Y
33 X
34 Y
36 X
37 Y
A opção -M
permite que o padrão corresponda a todos os caracteres de nova linha e a expressão regular corresponda a um X
, seguido por uma nova linha e, em seguida, todos os caracteres não pertencentes à nova linha e Y
.
Outra opção é escrever um pequeno script que salve a linha anterior se ela corresponder a X
e imprimi-la junto com a atual se a linha atual corresponder a Y
. Por exemplo, em awk
:
$ awk '{if(last~/X/ && /Y/){print last"\n"$0}last=$0}' file
31 X
32 Y
33 X
34 Y
36 X
37 Y
Ou Perl:
$ perl -ne '$last=~/X/ && /Y/ && print "$last$_"; $last=$_' file
31 X
32 Y
33 X
34 Y
36 X
37 Y
Tags grep text-processing awk sed