Procura um padrão e imprime linhas precedentes que começam com outro padrão

5

Eu preciso encontrar um padrão e, quando o encontrar, preciso procurar outro padrão anterior e imprimir todas as linhas entre elas.

Melhor exemplo:

1 a
2 a
3 a
4 a
5 a
6 b
7 c
8 d
9 xyz
10 xyz
11 a
12 a

Grep para xyz e, em seguida, grep para a primeira a anterior à linha xyz e imprime todas as linhas.

Saída (primeira ocorrência precedente de a , eu não me importo com outros a no arquivo):

5 a 
6 b
7 c
8 d
9  xyz
10 xyz
    
por user1413813 25.07.2014 / 23:57

4 respostas

1

Aqui está uma solução em Perl:

perl -nlE '
    if    (/a/)   { @buffer = ($_) }
    elsif (/xyz/) { push @buffer,$_; say for @buffer }
    else          { push @buffer,$_}
' your_file

Como isso funciona

Ele lê o arquivo linha por linha e faz uma de três coisas:

  1. Se a linha atual corresponder ao padrão a , ela atribuirá a linha atual à matriz @buffer .
  2. Se a linha atual corresponder ao padrão xyz , ele envia a linha atual para o buffer e imprime o conteúdo do buffer
  3. Se nenhum dos dois casos acima for verdadeiro, basta anexar a linha atual à matriz @buffer .

Assim, sempre que uma nova linha corresponder ao padrão a , o conteúdo do @buffer será apagado e substituído apenas pela linha atual. Isso garante que você encontrará o mais próximo a anterior xyz .

Você deve substituir os regexes que usei com os regexes reais relevantes para o seu caso.

    
por 26.07.2014 / 01:15
1

Eu acho que você poderia fazer algo como

grep -zPo '.*a(?s)(?(?!a).)*?xyz' file

(com o GNU grep, se sua versão é recente o suficiente para suportar a extensão PCRE) ou

pcregrep -Mo '.*a(?s)(?(?!a).)*?xyz' file

Se você deseja corresponder à segunda instância de xyz em sua saída, torne a correspondência gananciosa removendo a% final?, por exemplo, grep -zPo '.*a(?s)(?(?!a).)*xyz' file .

Talvez um teste melhor seja este, com padrões de caracteres múltiplos para as condições de início e parada; dado

$ cat file
1 abc    
2 abc
3 abc
4 abc
5 abc
6 bbc
7 cbc
8 dbc
9 xyz
10 xyz
11 abc
12 abc

então

$ grep -zPo '.*abc(?s)(?(?!abc).)*?xyz' file
5 abc
6 bbc
7 cbc
8 dbc
9 xyz
    
por 26.07.2014 / 03:53
1
tac file | sed '/xyz/,/a/!d' | tac

(se você não tem tac , seu comando tail pode ter um comando -r para fazer a mesma coisa).

    
por 15.08.2014 / 16:25
0

Se você não se importa com linhas em branco na saída, tente:

$ awk '
    !NF { next }
    /a/ { flag = 1; last = $0; next }
    last && flag { print last; print; last = 0; next}
    /xyz/ { print; flag = 0; next}
    flag
' file
5 a
6 b
7 c
8 d
9 xyz
10 xyz
    
por 26.07.2014 / 09:17