Imprimir linha X linhas antes / depois da linha encontrada

7

Eu quero procurar uma string específica em um determinado arquivo. Se eu encontrar a string, também quero imprimir as linhas da linha X antes (ou depois) dessa linha.

Isso pode ser feito com grep ou awk, ou eu preciso de uma combinação?

Eu gostaria de ter algo como isso , mas não com todas as linhas iniciais / anteriores antes ou depois de um hit, apenas o Xth.

Por exemplo, se minha entrada se parece com:

line1 with a pattern
line2
line3
line4 with a pattern
line5
line6
line7 with a pattern
...

Eu e. deseja procurar a palavra 'pattern' e produzir essa linha + a linha que tem 2 linhas depois disso, mas não a linha que segue diretamente a linha com o padrão. Então a saída desejada é:

line1 with a pattern
line3
line4 with a pattern
line6
line7 with a pattern
...
    
por MaVe 14.12.2013 / 11:25

4 respostas

13

grep fará isso para você, com as opções -A (após) e -B (antes) e -C (contexto). Um exemplo que costumo usar é:

   sudo lspci -vnn | grep -i net -A 12

porque este comando mostrará 12 linhas após a partida, o que inclui o driver usado para controlar a placa de rede (-i net). Em geral, o comando é:

  grep text_to_search -A n -B m file.extension

que produzirá m linhas antes da correspondência e n linhas após a correspondência. Ou você pode usar

 grep text_to_search -C n file.extension

para mostrar um total de n linhas ao redor do texto encontrado (metade antes, metade após a partida).

    
por 14.12.2013 / 14:09
2

Depois de analisar essa questão, acho que tenho que revisar meu comentário sobre a viabilidade de usar ferramentas GNU padrão sem script. Isso pode ser muito difícil de ser feito por causa dos casos especiais.

Se você não se importa em usar o awk, posso oferecer a seguinte solução. Este script context.awk ainda é bastante conciso:

{
    lines[NR] = $0
    if (dump[NR]) {
        print $0;
    if ($0 ~ Pattern) {
        if (NR-Delta in lines) {
            print "---"
            print lines[NR-Delta]
        }
        dump[NR+Delta] = 1
        print $0;
    }
    if (NR-Delta in lines) 
        delete lines [NR-Delta];
}

Tem que ser chamado da seguinte forma:

awk -v Delta=X -v Pattern=PATTERN -f context.awk sample.txt

em que X é a "distância do contexto" desejada e PATTERN do padrão de pesquisa. O script tenta separar vários contextos de padrão no arquivo, imprimindo linhas com --- entre elas. Então, por exemplo, o seguinte sample.txt

line1
line2
line3 XXX
line4
line5
line6
line7 XXX
line8
line9
line10 XXX
line11

usando esta chamada

awk -v Delta=3 -v Pattern=XXX -f context.awk sample.txt

produzirá o resultado seguinte

line3 XXX
line6
---
line4
line7 XXX
line10 XXX
---
line7 XXX
line10 XXX
    
por 16.12.2013 / 00:39
1

O seguinte comando sed parece funcionar para o caso que você descreve que eu gostaria de reescrever como: imprimir a linha correspondente ao meu padrão, não imprimir a linha imediatamente seguinte, também imprimir a linha duas linhas depois do meu padrão procurando correspondências de padrões.

sed -n -e '/with a pattern/ {h;n;n;H;x;p}' file

Parece um pouco feio, mas adicionando comandos adicionais n (ignorar linha, mover para o próximo) e H (manter essa linha anexando-a ao buffer de espera) você pode construir um keep / arbitrário Ignorar relacionamento seguindo uma correspondência de padrão.

Observe que, após a correspondência, inicialmente copiamos a linha correspondente para o buffer de retenção com o comando h . Por fim, trocamos o espaço de espera e de padrão por x e imprimimos o espaço de padrão com p . Neste ponto, sed continuará processando o arquivo linha por linha procurando outra correspondência.

Uma referência útil para os comandos sed pode ser encontrada aqui .

    
por 18.12.2013 / 01:54
0

grep -A2 <pattern> file | grep -B1 <pattern> | grep -v "\-\-" funciona para mim:

user@box /tmp $ grep -A2 "with a pattern" test.txt | grep -B1 "with a pattern" | grep -v "\-\-"
line1 with a pattern
line3
line4 with a pattern
line6
line7 with a pattern

user@box /tmp $ cat test.txt 
line1 with a pattern
line2
line3
line4 with a pattern
line5
line6
line7 with a pattern
    
por 18.12.2013 / 20:13

Tags