Remover linha com a correspondência de padrão e a próxima linha [duplicada]

20

Estou tentando remover todas as instâncias de uma correspondência de padrão de um arquivo se ele corresponder a um padrão. Se houver uma correspondência, a linha (completa) com o padrão correspondente e a próxima linha serão removidas.

A próxima linha sempre aparece após a linha com a correspondência de padrão, mas além disso aparece em outras áreas do arquivo.

Estou usando o grep e está excluindo todas as ocorrências da próxima linha no arquivo, como esperado.

Existe uma maneira de remover a próxima linha se, e somente se, ela estiver após a linha com a correspondência de padrões?

    
por kenuse 26.08.2014 / 23:59

5 respostas

24

Você pode usar sed com o N e d comandos e um {} block :

sed -e '/pattern here/ { N; d; }'

Para cada linha que corresponde a pattern here , o código no {} é executado. N também usa a próxima linha no espaço padrão e, em seguida, d exclui a coisa toda antes de passar para a próxima linha. Isso funciona em qualquer sed compatível com POSIX.

    
por 27.08.2014 / 00:08
5

A maioria dos sed s não imprime a última linha se você N on $ . Mas GNU sed será. Portanto, se o padrão que você deseja excluir estiver na última linha e você N será impresso. Às vezes é melhor manter o buffer cheio - como sempre mantendo 2 linhas exceto nas linhas que você não deseja imprimir. Você pode fazer assim:

seq 10 | sed -n 'x;/7/!g;//!p'

Esse é um exemplo com seq como entrada. Em cada linha, as trocas ocupam espaço e espaço padrão. Se a última linha mantida não corresponder a 7 (neste caso) ela irá sobrescrever o espaço de espera com a linha atual. Em seguida, ele verifica novamente que a linha que acabou de inserir - a linha atual - também não corresponde à 7 , caso contrário, não será impressa. Então, em cada linha, ele verifica a linha anterior e a atual.

1
2
3
4
5
6
9
10

E se seu padrão cair na última linha:

seq 10 | sed -n 'x;/10/!g;//!p' 

1
2
3
4
5
6
7
8
9

Outro exemplo, para demonstrar com mais clareza o que será e não será impresso:

sed -n 'x;/match/!g;//!p
' <<\DATA
    match 
    match 
    1not 
    2not 
    3not 
    4not 
    5not 
    match 
    6not 
    match                                                              
DATA

OUTPUT

2not
3not
4not
5not
    
por 27.08.2014 / 01:15
5

Uma solução awk:

awk '/pattern/    { matched=1; next }
     1 == matched { matched = 0; next }
                  { print }' input-file

A linha 1 procura por linhas que correspondam ao padrão, define um sinalizador e ignora a linha. A linha 2 pula uma linha quando o sinalizador está definido, mas redefine o sinalizador. A linha 3 imprime linhas que não foram ignoradas por uma das outras duas linhas.

Você pode digitar isso em uma linha, se quiser:

awk '/pattern/{matched=1;next} 1==matched{matched=0;next} {print}' input-file

Aqui está uma variação que permite controlar quantas linhas pular:

awk '/pattern/{skip=3;next} skip>0{--skip;next} {print}' input-file

Defina skip como o número de linhas que devem ser ignoradas (além da linha correspondente).

    
por 27.08.2014 / 14:17
4

Que tal

sed '/pattern/ {$!N;d;}' file
    
por 27.08.2014 / 00:07
3
cat sample
Pattern line
next after pattern line
this is another
random line
next after pattern line
has occured without.
now we have
another 
Pattern line
next after pattern line
let us see the output.

Agora, eu emito o comando abaixo.

sed -e '/Pattern \line/,+1d' sample

Esta é a saída que estou recebendo.

this is another
random line
next after pattern line
has occured without.
now we have
another 
let us see the output.

depois da linha padrão não é removida quando ocorre como uma linha separada, não próxima ao padrão .

De acordo com os comentários de Michael, a sintaxe acima é extensão GNU. Você pode tentar algo parecido,

sed -e '/Pattern \line/{N;d}' sample
    
por 27.08.2014 / 00:04