
Bom dia, isso é extremamente parecido com a perguntaGrep da última ocorrência de um padrão para outro padrão(vários meses), acrescentando 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, 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 também. Os padrões neste caso seriam 'Condição 1' e 'Condição 2':
saída.out:
...
Condition 1: A
data1
Condition 1: B
data2
Condition 2: C
data3
Condition 1: D
data4
Condition 1: E
data5
Condition 2: F
...
Eu gostaria de escrever um script awk (ou sed, mas imaginei que awk seria a ferramenta certa) para retornar:
Condition 1: B
data2
Condition 2: C
Condition 1: E
data5
Condition 2: F
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 em '/,/' é onde parece que estou tendo problemas. Queria saber se alguém tivesse algum conselho, ficaria muito grato. Muito obrigado por qualquer ajuda e tempo relacionado a esta questão.
Responder1
Tentar:
$ 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ávela
./Condition 1/{a=$0; f=1}
Se a linha atual contiver
Condition 1
, definas
para a linha atual e defina a variávelf
como 1.f && /Condition 2/{print a; f=0}
Se
f
for verdadeiro e a linha atual contiverCondition 2
, imprima a variávela
ef
volte para zero.
Responder2
Quando você quiser endereçamento reverso no processamento de texto, useex
Isso éPOSIX especificado, e é a forma programável de vi
(e vi
antecessor imediato de) - muito flexível.
printf '%s\n' 'g/Condition 2/?Condition 1?,.p' | ex output.out
Isso significa:
Para cada linha ( g
lobalmente) que corresponda ao padrão "Condição 2", pesquise para trás a instância imediatamente anterior de "Condição 1" e p
imprima todas as linhas dessa linha para a linha atual ( .
) (que é a linha com "Condição 2" em isto).
A saída da entrada fornecida é exatamente como você descreve.
Responder3
sed 'H;/PATTERN_1/h;/PATTERN_2/!d;x' infile
embora isso presuma que qualquer linha correspondente PATTERN_2
seja precedida por pelo menos uma linha correspondente PATTERN_1
. Para o caso mais geral, adicione outra condição para testar a PATTERN_1
presença no espaço do padrão antes de imprimir:
sed 'H;/PATTERN_1/h;/PATTERN_2/!d;x;/PATTERN_1/!d' infile
Responder4
Aqui está um pedaço maligno 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
Isto:
- lê o arquivo inteiro (usando as opções
-0777
e-n
), - divide onde a Condição 1 aparece (
split
), - filtra parágrafos onde a Condição 2 não aparece (
grep
), - em seguida, remove de cada parágrafo interessante todas as linhas que seguem a linha da Condição 2 (
map
).