Remover linha contendo determinada string e a seguinte linha

64

Eu uso isso

cat foo.txt | sed '/bar/d'

para remover linhas que contenham a string bar no arquivo.

Gostaria, no entanto, de remover essas linhas e a linha imediatamente a seguir . De preferência em sed , awk ou outra ferramenta disponível no MinGW32.

É uma espécie de reverso do que posso obter em grep com -A e -B para imprimir linhas correspondentes, bem como linhas antes / depois da linha correspondente.

Existe alguma maneira fácil de alcançá-lo?

    
por jakub.g 19.11.2012 / 17:41

5 respostas

66

Se você tem o GNU sed (Linux ou Cygwin não embarcado):

sed '/bar/,+1 d'

Se você tiver bar em duas linhas consecutivas, isso excluirá a segunda linha sem analisá-la. Por exemplo, se você tiver um arquivo de três linhas bar / bar / foo , a linha foo permanecerá.

    
por 20.11.2012 / 00:34
15

Se bar pode ocorrer em linhas consecutivas, você poderia fazer:

awk '/bar/{n=2}; n {n--; next}; 1' < infile > outfile

que pode ser adaptado para excluir mais de 2 linhas, alterando as 2 acima com o número de linhas a serem excluídas, incluindo a correspondente.

Se não, é fácil de fazer em sed com a solução @MichaelRollins ou:

sed '/bar/,/^/d' < infile > outfile
    
por 19.11.2012 / 21:10
12

Eu não sou fluente em sed, mas é fácil fazê-lo no awk:

awk '/bar/{getline;next} 1' foo.txt 

O script awk lê: para uma linha contendo a barra, obtenha a próxima linha (getline) e, em seguida, pule todo o processamento subseqüente (próximo). O padrão 1 no final imprime as linhas restantes.

Atualizar

Como apontado no comentário, a solução acima não funcionou com bar consecutivas. Aqui está uma solução revisada, que leva em consideração:

awk '/bar/ {while (/bar/ && getline>0) ; next} 1' foo.txt 

Agora continuamos lendo para pular todas as linhas / bar /.

    
por 19.11.2012 / 18:03
7

Você desejará usar os recursos de script do sed para fazer isso.

$ sed -e '/bar/ { 
 $!N
 d
 }' sample1.txt

Dados da amostra:

$ cat sample1.txt 
foo
bar
biz
baz
buz

O comando "N" acrescenta a próxima linha de entrada ao espaço padrão. Isso combinado com a linha da correspondência de padrões (/ bar /) será as linhas que você deseja excluir. Você pode então excluir normalmente com o comando "d".

    
por 19.11.2012 / 19:03
2

Se qualquer linha imediatamente após uma partida for removida, seu programa sed terá que considerar correspondências consecutivas. Em outras palavras, se você remover uma linha após uma correspondência que também corresponde, provavelmente você também deve remover a linha seguinte.

Ele é implementado simplesmente o suficiente - mas você precisa olhar para trás um pouco.

printf %s\n     0 match 2 match match \
                 5 6 match match match \
                 10 11 12 match 14 15  |
sed -ne'x;/match/!{g;//!p;}'
0
6
11
12
15

Funciona trocando espaço de espera e padrão para cada linha lida - então a última linha pode ser comparada com a atual a cada vez. Então, quando sed lê uma linha, ele troca o conteúdo de seus buffers - e a linha anterior é então o conteúdo de seu buffer de edição, enquanto a linha atual é colocada em espaço de espera.

Portanto, sed verifica a correspondência da linha anterior com match e, se o ! não encontrou as duas expressões na { function } , são executadas. sed irá g et o espaço de armazenamento sobrescrevendo o espaço de padrão - o que significa que a linha atual está nos espaços de retenção e padrão - e então // irá verificar se há uma correspondência com sua compilação regular mais recente expressão - match - e se ele não match é p rinted.

Isso significa que uma linha só é impressa se não match e a linha imediatamente anterior não match . Ele também renuncia a quaisquer trocas desnecessárias para seqüências de match es.

Se você quisesse uma versão que pudesse derrubar um número arbitrário de linhas que ocorressem depois de um match , seria necessário um pouco mais de trabalho:

printf %s\n    1 2 3 4 match  \
                match match 8  \
                9 10 11 12 13  \
                14 match match \
                17 18 19 20 21 |
sed -net -e'/match/{h;n;//h;//!H;G;s/\n/&/5;D;}' -ep

... substitua o 5 pelo número de linhas (incluindo a linha correspondente) que você gostaria de remover ...

1
2
3
4
12
13
14
21
    
por 15.12.2015 / 03:08