Imprime intervalos desde a última ocorrência de um determinado padrão até a primeira ocorrência de outro padrão

5

Bom dia, isso é extremamente semelhante à pergunta Grep Da Última Ocorrência de um Padrão para Outro Padrão (vários meses), enquanto adiciona um pouco mais de detalhes.

Estou tentando escrever um script UNIX para um arquivo com vários padrões duplicados, seguido pelo padrão que estou procurando. No entanto, eu não tenho 'tac' ou 'tail -r' (usando o emulador UNIX, MKS Toolkit) e estou procurando retornar a última ocorrência de Pattern1 antes de Pattern2, seguida pelos dados entre Pattern1 e Pattern2 e, em seguida, Pattern2 Além disso. Os Padrões neste caso seriam 'Condição 1' e 'Condição 2':

output.out:

...
Condition 1: A
data1
Condition 1: B
data2
Condition 2: C
data3
Condition 1: D
data4
Condition 1: E
data5
Condition 2: F
...

Gostaria de escrever um script do awk (ou sed, mas imaginei que o awk seria a ferramenta certa) para retornar:

Condition 1: B
data2
Condition 2: C
Condition 1: E
data5
Condition 2: F

Eu acho que é alguma forma da linha abaixo, mas não consigo acertar a sintaxe:

awk '/Condition 1/ {acc = $0;} /,/Condition 2/ {print ?}' output.out

Trabalhar no '/, /' é onde eu pareço ter problemas. Estava se perguntando se alguém tinha algum conselho, seria muito apreciado. Muito obrigado por qualquer ajuda e tempo relacionado a esta questão.

    
por Henry 21.11.2017 / 19:54

4 respostas

5

Tente:

$ awk 'f{a=a"\n"$0} /Condition 1/{a=$0; f=1} f && /Condition 2/{print a; f=0}' output.out 
Condition 1: B
data2
Condition 2: C
Condition 1: E
data5
Condition 2: F

Como funciona

  • f{a=a"\n"$0}

    Se a variável f for verdadeira (diferente de zero), anexe a linha atual ao final da variável a .

  • /Condition 1/{a=$0; f=1}

    Se a linha atual contiver Condition 1 , defina s para a linha atual e defina a variável f para 1.

  • f && /Condition 2/{print a; f=0}

    Se f for verdadeiro e a linha atual contiver Condition 2 , imprima a variável a e defina f de volta para zero.

por 21.11.2017 / 20:04
5

Quando você quiser um endereçamento reverso no processamento de texto, use ex

POSIX especificado , e é a forma de script de vi (e vi do predecessor imediato) - muito flexível.

printf '%s\n' 'g/Condition 2/?Condition 1?,.p' | ex output.out

Isso significa:

Para cada linha ( g lobally) correspondente ao padrão "Condição 2", pesquise a instância imediatamente anterior de "Condição 1" e p rint todas as linhas dessa linha para a linha atual ( . ) (que é a linha com "Condição 2").

A saída na entrada fornecida é exatamente como você descreve.

    
por 22.11.2017 / 00:13
4
sed 'H;/PATTERN_1/h;/PATTERN_2/!d;x' infile

embora isso pressuponha que qualquer linha que corresponda a PATTERN_2 seja precedida por pelo menos uma linha correspondente a PATTERN_1 . Para o caso mais geral, adicione outra condição para testar a presença de PATTERN_1 no espaço de padrão antes de imprimir:

sed 'H;/PATTERN_1/h;/PATTERN_2/!d;x;/PATTERN_1/!d' infile
    
por 21.11.2017 / 20:35
4

Aqui está um pouco malvado de perl:

perl -0777 -ne '
    my $c1 = qr/Condition 1/;
    my $c2 = qr/Condition 2/;
    print for map {s/$c2.*?\n\K.*//s; $_}
              grep {/$c2/}
              split /(?=$c1)/ms;
' output.out

  • lê o arquivo inteiro (usando as opções -0777 e -n ),
  • divide-a quando a Condição 1 aparecer ( split ),
  • filtra os parágrafos onde a Condição 2 não aparece ( grep ),
  • então remove de cada parágrafo interessante quaisquer linhas seguindo a linha Condição 2 ( map ).
por 21.11.2017 / 21:03