Como excluir cada segunda linha de um arquivo?


25

Arquivo:

Data inserted into table. Total count 13
No error occurred
Data inserted into table. Total count 45
No error occurred
Data inserted into table. Total count 14
No error occurred
Data inserted into table. Total count 90
No error occurred

Arquivo de saída esperado:

Data inserted into table. Total count 13
Data inserted into table. Total count 45
Data inserted into table. Total count 14
Data inserted into table. Total count 90

Eu quero que a saída fique assim: cada segunda linha será excluída, mas não haverá espaço entre as linhas.


5
Deseja excluir cada segunda linha ou todas as linhas que contêm "Nenhum erro ocorreu" ? E se duas linhas consecutivas tivessem "Nenhum erro ocorreu" ?
Tulains Córdova

1
@ user1598390 Acho que ... nesse caso, grep -v "No error occurred" fileeste comando deve funcionar ... o que @paul respondeu. No arquivo de saída, não haverá linhas contendo "Nenhum erro ocorreu" nesta parte.
Pmaipmui

1
Então o título da pergunta é enganoso.
Tulains Córdova 06/08/2015

Respostas:


36

Com sed:

sed -e n\;d <file

Com o POSIX awk:

awk 'FNR%2' <file

Se você tem mais idade awk(como oawk), precisa:

oawk 'NR%2 == 1' <file

Com ex:

$ ex file <<\EX
:g/$/+d
:wq!
EX

irá editar o arquivo no local.

  • g marcar um comando global
  • /$/ combinar todas as linhas
  • +d exclua a próxima linha
  • wq! salve todas as alterações

Essa abordagem compartilha o mesmo ideal com a sedabordagem, exclua todas as próximas linhas da linha atual, começando da linha 1.

Com perl:

perl -ne 'print if $. % 2' <file

e perl6:

perl6 -ne '.say if $*IN.ins % 2' <file
perl6 -ne '.say if ++$ % 2' <file

Sim ... está funcionando ... :) ... o primeiro está funcionando .... eu também tentei o segundo .. está dizendo `awk: syntax error line1 awk: saindo perto da linha 1 '
pmaipmui

sed -en \; d <arquivo ~ Sim seu @cuonglm de trabalho ...
pmaipmui

1
Eu suponho que você usou em n\;dvez de 'n;d'salvar um caractere precioso, mas essa lógica desaparece quando você desnecessariamente usa o -ecomutador e o redirecionamento de arquivo <!
Tom Fenech

1
@ Geek: É apenas uma versão mais curta de sed -e 'n;d', salvar um personagem.
cuonglm

1
@ Geek: ncomando escreve o espaço do padrão na saída padrão, se -nfoi usado, depois substitui o espaço do padrão pela próxima linha. Aqui todas as linhas ímpares serão impressas n, as linhas pares serão lidas no espaço do padrão, mas dserão excluídas imediatamente pelo comando `.
cuonglm

62

Resolver isso excluindo cada segunda linha pode estar sujeito a erros (por exemplo, quando o processo às vezes gera duas linhas significativas em vez de uma). Talvez seja melhor filtrar o lixo:

grep -v "No error occurred" file

Pode ser executado como filtro, você pode adicionar mais padrões de lixo aqui e melhorar o resultado.


9
+1 por destacar que às vezes a segunda linha é importante!
Kaz Wolfe

12

Em resposta à pergunta, com o GNU sed:

sed '0~2d' file

excluirá cada segunda linha, mas eu gostaria de oferecer linhas de filtro por este conteúdo:

sed '/Data/! d' file

ou com o mesmo resultado

sed '/No error/d' file

sed '/ Não / d erro' arquivo ~ dá as @Costas saída desejados
pmaipmui

5
Note que as duas últimas são maneiras complicadas de escrever grep Dataegrep -v 'No error'
Stéphane Chazelas

5

Aqui está uma maneira de usar sed:

sed -n 'p;n' filename

Outra maneira com o GNU sed:

sed -n '1~2p' filename

Saída dos comandos acima:

Data inserted into table. Total count 13
Data inserted into table. Total count 45
Data inserted into table. Total count 14
Data inserted into table. Total count 90

O que você quer dizer com dizer shortest way using sed?
precisa saber é

Qual é o motivo no gcomando? sed -n 'p;n'basta.
Costas

@cuonglm: quero dizer uma maneira simples de fazer. A propósito, removi essa palavra. :)
serenesat

@ Costas: Obrigado! Acabei de verificar, está funcionando sem g. g removido do comando. :)
serenesat

4

Você pode tentar com awk:

awk 'NR % 2 != 0' file

ou você pode imprimir apenas linhas contendo Data inserted:

awk '$0 ~ /Data inserted/' file

Eu tentei tanto de você responde e ambos estão trabalhando ... :)
pmaipmui

3

Outra resposta, você pode usar o vi / vim!

qdjddq

E se o seu arquivo tiver 500 linhas (por exemplo), digite

250 @ d

E então para escrever e sair do tipo

: x

Ou se algo der errado e você não quiser salvar:

: q!

Explicação:

q      #Start Recording
 d     #Put the recording into register 'd'
  j    #Move the cursor down
   dd  #Delete the line
     q #Stop recording


250    #Number of repeats
   @d  #Playback the recording in register 'd'.

2

Aqui está uma maneira bem diferente de fazer isso:

< file paste - - | cut -f1

Isso pressupõe que as linhas com números ímpares não contenham tabulações. Se o fizerem, será necessário escolher outro caractere separador, por exemplo, :aqui:

< file paste -d: - - | cut -d: -f1

1
Eu tinha isso em mente quando vi a pergunta pela primeira vez ... Seria interessante executar um teste de velocidade sedcom um arquivo enorme (por exemplo, 20 mil linhas). De qualquer forma, +1 mas realmente, a dores de cabeça evitar, escolher um delimitador que é pouco provável de ocorrer em um arquivo de texto, como $'\002'...
don_crissti

@don_crissti sim, o uso de um caractere não imprimível para o separador é uma boa ideia. E sim, isso é mensurável mais rápido que a solução sed. Eu criei um arquivo de teste com seq 100000000 > 100mil.txt. A paste|cutsolução terminou em cerca de 7,5 segundos, contra quase 12 na sedsolução. Parece ser repetível. grepé mais rápido. Ubuntu 14.04 com ferramentas GNU padrão.
Digital Trauma

Yep, paste+ cutsão altamente otimizado para o seu trabalho tão sem surpresa a sua combinação é muito muito rápido ...
don_crissti

1

Outra opção (mais curta)

sed 'n; d' file

3
É mais longo que o meu sed n\;d, adicionar -eé apenas meu hábito.
cuonglm

0

Também resolve o problema, embora seja um pouco mais lento:

vim -c "%normal jdd" -c "wq" file
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.