Qual é a melhor maneira de remover um segmento de um arquivo de texto?


Respostas:


12

você poderia tentar:

cat textfile | head -n 45 | tail -n 26

ou

cat textfile | awk "20 <= NR && NR <= 45" 

atualizar:

Como Mahomedalid apontou, catnão é necessário e um pouco redundante, mas contribui para um comando limpo e legível.

Se cato incomoda, uma solução melhor seria:

<textfile awk "20 <= NR && NR <= 45"

2
awk NR==20,NR==45 textfilefunciona também e lê com facilidade.
ephemient 16/09/10

I como o uso de stdin mais, tem alguma consistência global com o resto do nix
Stefan

1
A leitura dos argumentos da linha de comando também tem consistência com outros utilitários UNIX, e meu ponto principal foi demonstrar o ,operador de intervalo do awk .
ephemient 17/09/10

lol, eu quis dizer @adam. mas sim, eu gosto de sua sugestão
Stefan

Acho que a resposta do @ ephemient é a melhor aqui. Caso contrário, os comandos são bastante enigmáticos.
Léo Léopold Hertz,

13

Ainda mais simples:

sed -n '20,45p;45q' < textfile

O sinalizador -n desativa a saída padrão. O "20,45" aborda as linhas 20 a 45, inclusive. O comando "p" imprime a linha atual. E oq sai depois de imprimir a linha.


1
+1 bom, eu gosto, mas sua linha de 20 a 45 :)
Stefan

1
ok ok, eu editei para dizer 20,45 :-)
dkagedal

A remoção do qcomando (tudo a partir de ;) melhorou o desempenho para mim ao extrair uma única linha 26995107 de um arquivo de 27169334 linhas.
Ruslan

6

Esta não é uma resposta, mas não pode publicá-la como um comentário.

Outra maneira (muito rápida) de fazer isso foi sugerida por mikeserv aqui :

{ head -n 19 >/dev/null; head -n 26; } <infile

Usando o mesmo arquivo de teste aqui e o mesmo procedimento, aqui estão alguns parâmetros de referência (extração das linhas 1000020-1000045):

mikeserv :

{ head -n 1000019 >/dev/null; head -n 26; } <iplist

real    0m0.059s

Stefan :

head iplist -n 1000045 | tail -n 26

real    0m0.054s

Essas são, de longe, as soluções mais rápidas e as diferenças são insignificantes (para uma única passagem) (tentei com diferentes faixas: algumas linhas, milhões de linhas, etc.).

Fazer isso sem o cano pode oferecer uma vantagem significativa, no entanto, para um aplicativo que precisa procurar em vários intervalos de linhas da mesma maneira, como:

for  pass in 0 1 2 3 4 5 6 7 8 9
do   printf "pass#$pass:\t"
     head -n99 >&3; head -n1
done <<1000LINES 3>/dev/null
$(seq 1000)
1000LINES

... que imprime ...

pass#0: 100
pass#1: 200
pass#2: 300
pass#3: 400
pass#4: 500
pass#5: 600
pass#6: 700
pass#7: 800
pass#8: 900
pass#9: 1000

... e lê o arquivo apenas uma vez.


As outras sed/ awk/ perlsolutions leem o arquivo inteiro e, como se trata de arquivos enormes, eles não são muito eficientes. Joguei algumas alternativas que exitou quit após a última linha no intervalo especificado:

Stefan :

awk "1000020 <= NR && NR <= 1000045" iplist

real    0m2.448s

vs.

awk "NR >= 1000020;NR==1000045{exit}" iplist

real    0m0.243s

dkagedal ( sed):

sed -n 1000020,1000045p iplist

real    0m0.947s

vs.

sed '1,1000019d;1000045q' iplist

real    0m0.143s

Steven D :

perl -ne 'print if 1000020..1000045' iplist

real    0m2.041s

vs.

perl -ne 'print if $. >= 1000020; exit if $. >= 1000045;' iplist

real    0m0.369s

+1 Acho que esta é a melhor resposta aqui! Seria bom obter quanto tempo leva para isso awk NR==1000020,NR==1000045 textfileem seu sistema.
Léo Léopold Hertz,

3
ruby -ne 'print if 20 .. 45' file

1
um companheiro Rubyist, você tem o meu voto senhor
Stefan

1
Enquanto estamos nisso, por que não python -c 'import fileinput, sys; [sys.stdout.write(line) for nr, line in enumerate(fileinput.input()) if 19 <= nr <= 44]'também? :-P Isso é algo que Ruby, modelado após o Perl, inspirado no awk / sed, pode fazer facilmente.
ephemient 17/09/10

2

Como sed e awk já foram usados, aqui está uma solução perl:

perl -nle "print if ($. > 19 && $. < 46)" < textfile

Ou, como apontado nos comentários:

perl -ne 'print if 20..45' textfile

2
O que há com todos esses personagens extras? Não há necessidade de remover e adicionar novamente novas linhas, o flip-flop assume uma comparação com o número da linha e o operador de diamante percorre argumentos, se houver. perl -ne'print if 20..45' textfile
ephemient

1
Agradável. nulo é um pouco de reflexo, suponho que, quanto ao resto, não tenho desculpa a não ser a ignorância.
Steven D
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.