Como imprimir linhas entre o mesmo padrão com a ocorrência múltipla?

3

É necessário extrair as linhas entre o mesmo padrão e a ocorrência especificada do padrão de pesquisa

como se eu quiser obter as linhas entre 1º e amp; 2ª ocorrência ou linhas entre a 3ª e 4ª ocorrência do padrão de busca. Onde não houver linhas entre o padrão, se não houver linhas entre o padrão, a saída deve ficar em branco

Exemplo: -

Line 1
Line 2
Line 3
Pattern
Line 5
Line 6
Line 7
Pattern
Line 8
Line 9
Pattern
Line 11
Line 12
Pattern
Line 13
Pattern
Pattern

Saída esperada Linhas entre a 1ª e a 2ª ocorrência

Line 5
Line 6
Line 7

Linhas entre a 3ª e 4ª ocorrência

Line 11
Line 12
    
por Vasanta Koli 18.05.2017 / 08:40

4 respostas

2

Com base em esta resposta ,

awk '/Pattern/{n+=1}; n % 2 == 1 && ! /Pattern/ {print > "output"((n-1)/2)}' input_file 

Explicação

  • /Pattern/{n+=1} : quando você corresponde a Pattern , incrementa n por 1.
  • n % 2 == 1 && ! /Pattern/ : faça o seguinte, então n é ímpar, ou seja, após cada padrão alternativo. Além disso, ignore as linhas com Pattern nelas.
  • {print > "output"((n+1)/2)}' : se o item acima for válido, imprima essa linha em um arquivo chamado outputx , em que x é ((n+1)/2) , ou seja, output1 , output2 , output3
por 18.05.2017 / 09:10
1

Abordagem alternativa de AWK

 $ awk -v start=3  '/Pattern/{n++;next};n==start;n==start+1{exit}' input.txt                                                     
Line 11
Line 12

$ awk -v start=2 '/Pattern/{n++;next};n==start;n==start+1{exit}' input.txt                                                      
Line 8
Line 9

Explicação

A maneira como isso funciona é bastante simples:

  • usando -v flag definimos uma variável que incrementamos se encontrarmos o padrão correspondente e passarmos para a próxima linha (essa é a parte /Pattern/{n++;next} do código)
  • no awk se a condição for verdadeira, isso é automaticamente um sinal para imprimir coisas, portanto n==start pode ser visto como n==start{print} .
  • codeblock final onde olhamos se chegamos ao próximo padrão é n==start+1 {exit} . Say we wanted to print lines between 4th and 5th pattern occurrence. This will mean that when n == 4 + 1 'o código sai

Se estivéssemos fazendo code-golf, poderíamos tornar isso ainda mais curto mudando apenas a variável start para algo como -v s=1 , o que encurta o código da seguinte forma:

awk -v s=3  '/Pattern/{n++;next};n==s;n==s+1{exit}'

Suposições:

  • GNU awk
  • estamos lendo entre padrões consecutivos, ou seja, entre a correspondência n e n+1

Generalizando a abordagem

E se quiséssemos imprimir linhas entre o padrão 2 e o padrão 4? Usando alguns truques usados no exemplo anterior, podemos fazer isso também:

$ awk -v start=2 -v finish=4 '/Pattern/{n++;next};n==finish{exit};n>=start' input.txt                                           
Line 8
Line 9
Line 11
Line 12

Observe que aqui definimos outra variável, finish , para saber onde parar. Dessa forma, n==finish parará de imprimir as linhas. Observe também que n==finish{exit} vem antes de n>=start , o que nos permite evitar a impressão redundante da mesma linha na qual devemos sair.

    
por 18.05.2017 / 09:35
0

com sed :

sed -n '/Pattern/!d;:a
n;//! {w file1.txt
ba
};:b 
n;//! bb
:c
n;//q;w file2.txt
bc
' file

Com POSIX sed Você tem que fazer 3 argolas como este para os jogos ambos eo in-between, como você não pode gerar nomes de arquivo de dentro do script.

    
por 18.05.2017 / 09:26
0
start=3; # these can only be positive integers
 stop=4; # stop > start

perl -lne "// or print if /Pattern/ && ++\$a == $start ... // && ++\$a == $stop" data.in

A solução Perl usa o operador de intervalo ... , onde dois operandos agem como flip-flops: = > contanto que o primeiro operando seja falso, ... retorna falso. Assim que o primeiro operando for verdadeiro, o ... retorna verdadeiro. Ele só será falso quando o segundo operando se tornar verdadeiro. A subtilidade surge devido à característica de que o operando1 não é avaliado assim que se torna verdadeiro e o operando2 não é avaliado enquanto o operando1 é falso.

sed -nE "
   /Pattern/!d
   x
      s/\$/./
      /^[.]{$start}\$/!{x;d;}
   x

   n

   :loop
      p;n
      /Pattern/{
         x
            s/\$/./
            /^.{$stop}\$/q
         x
      }
   bloop
" data.in

a solução sed usa o espaço de espera para manter uma contagem do número de vezes que o padrão é visto. Continuamos a rejeitar linhas, desde que o número inicial de padrões não seja visto. Assim que o padrão $ start-th chega, nós entramos em um loop que continua lendo a próxima linha, imprimindo e ao mesmo tempo medindo se o padrão $ stop-th é visto. Uma vez vista, saímos rapidamente.

    
por 18.05.2017 / 12:30

Tags