Grep vários padrões e imprimir um número diferente de linhas abaixo de cada um dos padrões?

2

Eu estou tentando encontrar uma maneira de grep / awk vários padrões e, em seguida, imprimir um certo número de linhas abaixo do primeiro padrão e um determinado número de linhas abaixo do segundo padrão. Por exemplo

  ....
  other lines
  ....
###Pattern 1####
line 1
line 2
line 3 
 ....
 other lines
 ....
####Pattern 2####
line 1
line 2
line 3 
line 4
 ....
 other lines
 ....

Então, o que eu quero fazer é encontrar os dois padrões no arquivo e imprimir o primeiro padrão e as três linhas anteriores abaixo, depois o segundo padrão e as quatro linhas precedentes abaixo do segundo padrão.

Para que minha saída desejada se pareça com:

####Pattern 1####
line 1
line 2
line 3
####Pattern 2####
line 1
line 2
line 3 
line 4

Saída desejada atualizada Então, antes que eu não fosse tão claro, peço desculpas, pode haver vários padrões. Então, o que eu espero alcançar é um resultado que se pareça com o seguinte:

####Pattern 1####
line 1
line 2
line 3
####Pattern 2####
line 1
line 2
line 3 
line 4
-----
####Pattern 1####
line 1
line 2
line 3
####Pattern 2####
line 1
line 2
line 3 
line 4
-----
 and so on
    
por pdm 07.07.2015 / 20:06

2 respostas

1

Sem dúvida, algumas abordagens mais elegantes, mas aqui está uma maneira

# awk '/Pattern 1/{for(c=0;c<4;c++){print;getline}}/Pattern 2/{for(c=0;c<5;c++){print;getline}}' foo
###Pattern 1####
line 1
line 2
line 3
####Pattern 2####
line 1
line 2
line 3
line 4
#

Marginalmente mais elegante:

# awk '/Pattern 1/{c=4}/Pattern 2/{c=5}{while(c-->0){print;getline}}' foo
###Pattern 1####
line 1
line 2
line 3
####Pattern 2####
line 1
line 2
line 3
line 4
#

E para inserir 5 hífens no conjunto correspondente, tente isso

# awk '/Pattern 1/{c=4}/Pattern 2/{c=5}{while(c-->0){print;getline;x=1}if(x){print "-----";x=0}}' foo
###Pattern 1####
line 1
line 2
line 3
-----
####Pattern 2####
line 1
line 2
line 3
line 4
-----
#

Ou para um "-----" no final, use:

# awk '/Pattern 1/{c=4}/Pattern 2/{c=5}{while(c-->0){print;getline}}END{print "-----"}' foo
###Pattern 1####
line 1
line 2
line 3
####Pattern 2####
line 1
line 2
line 3
line 4
-----
#
    
por 07.07.2015 / 20:18
2
sed -ne'/pattern1/{:1' -e'$p;N;s/\n/&/[num]; to' -eb1 -e\} \
     -e'/pattern2/{:2' -e'$p;N;s/\n/&/[num]; to' -eb2 -e\} \
     -ed -e:o -eh      -e'y/\n-/-\n/;s/[^-]*//g' -e'H;x;p'

Isso imprimirá quantos - traços após um bloco de correspondência, pois há novas linhas que seguem essa correspondência. E assim, se você quisesse 4 linhas após cada partida de pattern1 e 2 após cada partida de pattern2, você obteria uma linha divisória adicional impressa entre cada bloco de 4 hífens na cauda de um bloco de padrão1 e 2 hífens na cauda de um padrão2 quadra. Isso é tudo verdade exceto quando a última linha é encontrada ao coletar a cauda de cada uma - nesse caso, tudo entre a última linha e a correspondência de padrões é impresso, mas nenhum hífens é acrescentado.

Você pode notar que grande parte do código no script sed acima é bastante redundante. Basicamente, estamos apenas implementando um tipo idêntico de loop para cada correspondência possível. É graças às regras de sintaxe muito simples de sed , como é evidenciado acima, que torna o script sed tão eminentemente programável. Em outras palavras, como a sintaxe do sed é básica, é um assunto simples escrever um script que possa escrever um script sed .

Por exemplo, esta tarefa pode ser facilmente parametrizada para funcionar com qualquer número de padrões e contagens de linha de acompanhamento associadas:

amatch(){  sed ${2:+"-ne$(n=0;                   \
    while  [ "$#" -gt "$((!!(n+=1)))" ];         \
    do     printf "\n/%s/{:$n\n\t%s;to\n\t%s\n}" \
                  "$1" "\$p;N;s/\n/&/$2" "b$n";  \
           shift 2;                              \
    done;  printf "\nd;:o\n\t%s\n\t%s\n\tH;x;p"  \
                  'h;y/\n-/-\n/' 's/[^-]*//g'    \
)"}; }

Contanto que amatch() seja chamado com 2 ou mais parâmetros, ele criará um script sed exatamente como o acima, e escreverá um loop para cada par.

Primeiramente, ele cria e imprime um script sed em um subshell e, depois, sed o executa contra stdin.

Então, quando eu faço:

seq 30 | amatch \[45] 5 1$ 2

O laço while do shell monta e imprime para o comando substituir um script que se pareça com:

/[45]/{:1
    $p;N;s/\n/&/5;to
    b1
}
/1$/{:2
    $p;N;s/\n/&/2;to
    b2
}
d;:o
    h;y/\n-/-\n/
    s/[^-]*//g
    H;x;p

E sed avalia isso contra stdin e imprime ...

1
2
3
--
4
5
6
7
8
9
-----
11
12
13
--
14
15
16
17
18
19
-----
21
22
23
--
24
25
26
27
28
29
-----
    
por 07.07.2015 / 21:59

Tags