Remova a linha que contém determinada string e a linha seguinte

Eu uso isso

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

para remover linhas contendo a string bar no arquivo.

No entanto, gostaria de remover essas linhas e a linha diretamente depois disso . De preferência em sed, awk ou outra ferramenta que “esteja disponível no MinGW32.

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

Existe alguma maneira fácil de conseguir isso?

Comentários

  • Apenas para informações: Eu ‘ estou analisando logs em que as entradas são de duas linhas. Portanto, quero encontrar uma entrada que corresponda ao padrão e removê-la, assim como a próxima linha. Portanto, eu não ‘ não preciso lidar com linhas de correspondência consecutivas, mas agradeço de qualquer forma por suas respostas serem completas!

Resposta

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

sed "/bar/,+1 d" 

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

Comentários

  • +1 para o comprimento 🙂 Em particular exemplo eu não ‘ t tenho bar s consecutivos, então este é muito fácil de lembrar.
  • sed '/bar/d' se você apenas deseja ” Remover a linha contendo determinada string ” e não b> o próximo.
  • Se eu quiser remover todas as linhas depois da matemática, então?
  • @Pandya Isso ‘ é diferente. Você pode usar, por exemplo, sed '/math/q'
  • @ A.K. Se você deseja apenas excluir a linha correspondente, ‘ é ainda mais simples: sed '/bar/d'

Resposta

Se bar pode ocorrer em linhas consecutivas, você pode 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, “é feito facilmente em sed com a solução @MichaelRollins” ou:

sed "/bar/,/^/d" < infile > outfile 

Comentários

  • A outra vantagem na solução AWK é que posso substituir /bar/ por /bar|baz|whatever/. Em sed, essa sintaxe não ‘ não parece funcionar.
  • @ jakub.g, tenho GNU sed ( v4.4 agora). Não tenho certeza sobre os outros. O que eu sei é que ele usa a ” básica ” sintaxe de expressão regular por padrão, é por isso que seu exemplo não ‘ t trabalho. Para conseguir o que deseja, você pode colocar uma barra invertida na frente de cada linha vertical ou pode pedir a sed para usar ” estendido ” expressões regulares. Mais informações aqui: gnu.org/software/sed/manual/html_node/… . Observe que isso se aplica a grep também. Aqui ‘ é meu próprio exemplo de trabalho: echo $'0a\n1b\n2c' | sed '/0a\|1b/d'.

Resposta

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

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

O O script awk lê: para uma linha contendo bar, pegue a próxima linha (getline) e pule todo o processamento subsequente (próximo). O padrão 1 no final imprime as linhas restantes.

Atualizar

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

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

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

Comentários

  • Para replicar grep -A 100%, você também precisa lidar com qualquer número de linhas corretamente (removendo o bloco inteiro e 1 linha depois).

Resposta

Você vai querer usar os recursos de script do sed para fazer isso.

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

Dados de amostra:

$ cat sample1.txt foo bar biz baz buz 

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

Comentários

  • Como faço para digitar uma nova linha no console? Ou é somente script?
  • @ jakub.g: com GNU sed: sed -e '/bar/{N;d}' sample1.txt

Resposta

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

É implementado de forma simples – mas você precisa olhar um pouco para trás .

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 os espaços de espera e padrão para cada linha lida – assim, a última linha pode ser comparada com a atual a cada vez. Portanto, quando sed lê uma linha, ele troca o conteúdo de seus buffers – e a linha anterior é o conteúdo de seu buffer de edição, enquanto a linha atual é colocada em um espaço de retenção.

Portanto, sed verifica a linha anterior para obter uma correspondência com match , e se seu ! não encontrou as duas expressões na { função } são executadas. sed irá g et o espaço de espera substituindo o espaço de padrão – o que significa que a linha atual está então nos espaços de espera e padrão – e então // verificará se há uma correspondência com sua expressão regular compilada mais recentemente – match – e se não match , é p reduzido.

Isso significa que uma linha só é impressa se não match e a linha imediatamente anterior não match . Também precede qualquer troca desnecessária por sequências de match es.

Se você quisesse uma versão que pudesse perder um número arbitrário de linhas ocorrendo após 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 

Deixe uma resposta

O seu endereço de email não será publicado. Campos obrigatórios marcados com *