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/
. Emsed
, 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 agrep
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