Remoção eficiente de cabeçalho no local para arquivos grandes usando sed?

24

Os comandos abaixo podem levar alguns minutos, dependendo do tamanho do arquivo. Existe algum método mais eficiente?

sed -i 1d large_file 
Cheng
fonte

Respostas:

34

Tente ed:

ed <<< $'1d\nwq' large_file

Se esse "grande" significa cerca de 10 milhões de linhas ou mais, use melhor tail. Não é capaz de editar no local, mas seu desempenho torna essa falta perdoável:

tail -n +2 large_file > large_file.new

Edite para mostrar algumas diferenças de horário:

( awkcódigo de Jaypal adicionado para ter tempos de execução na mesma máquina (CPU 2.2GHz).)

bash-4.2$ seq 1000000 > bigfile.txt # further file creations skipped

bash-4.2$ time sed -i 1d bigfile.txt
time 0m4.318s

bash-4.2$ time ed -s <<< $'1d\nwq' bigfile.txt
time 0m0.533s

bash-4.2$ time perl -pi -e 'undef$_ if$.==1' bigfile.txt
time 0m0.626s

bash-4.2$ time { tail -n +2 bigfile.txt > bigfile.new && mv -f bigfile.new bigfile.txt; }
time 0m0.034s

bash-4.2$ time { awk 'NR>1 {print}' bigfile.txt > newfile.txt && mv -f newfile.txt bigfile.txt; }
time 0m0.328s
homem a trabalhar
fonte
No caso de tail, eu prefiro contar o tempo para fazer tanto remover a primeira linha e substituir bigfile.txtcom bigfile.new.
rozcietrzewiacz
@rozcietrzewiacz, seu ponto está correto. Obrigado. Atualizada.
manatwork
Isso é muito legal! Eu fiz o mesmo com awke obteve o seguinte resultado -[jaypal:~/Temp] seq 1000000 > bigfile.txt [jaypal:~/Temp] time awk 'NR>1 {print}' bigfile.txt >newfile.txt real 0m0.649s user 0m0.601s sys 0m0.033s
jaypal singh
1
@ Jaypal, adicionei seu código à lista de alternativas. Na minha máquina, era ainda mais rápido. Estranho, eu esperava que awko desempenho estivesse mais próximo seddo. (Nota para mim mesma: nunca espera - de teste.)
manatwork
Essa foi a melhor solução no meu caso: tail -n +2 bigfile.txt > bigfile.new && mv -f bigfile.new bigfile.txt;estou usando um único arquivo com um bloqueio para acompanhar uma única lista de tarefas usada por vários processos. Comecei com o que o cartaz inicial utilizado: sed -i 1d large_file . Isso estava causando o bloqueio do arquivo por 1-2 segundos. A tail/mvcombinação é concluída quase instantaneamente. Obrigado!
21420 Chris
6

Não há como remover coisas com eficiência desde o início de um arquivo. A remoção de dados desde o início requer a reescrita de todo o arquivo.

Truncar a partir do final de um arquivo pode ser muito rápido (o sistema operacional precisa apenas ajustar as informações de tamanho do arquivo, possivelmente limpando os blocos não utilizados). Isso geralmente não é possível quando você tenta remover da cabeça de um arquivo.

Teoricamente, poderia ser "rápido" se você removesse todo um bloco / extensão exatamente, mas não há chamadas de sistema para isso, então você teria que confiar na semântica específica do sistema de arquivos (se houver). (Ou ter alguma forma de deslocamento dentro do primeiro bloco / extensão para marcar o início real do arquivo, eu acho. Nunca ouvi falar disso também.)

Esteira
fonte
Se o arquivo for muito grande, é provável que a sobrecarga de E / S seja (possivelmente muito) maior que a sobrecarga da CPU necessária para processar o fim das linhas.
Mat
Você está certo. No entanto, pode haver diferença na maneira como as ferramentas acessam o conteúdo do arquivo. O melhor é não processar linha por linha quando não for necessário ou, pelo menos, não ler linha por linha quando não for necessário.
manatwork
2
Estou surpreso que a diferença seja tão grande nos seus resultados e possa reproduzi-la com esse tamanho de arquivo aqui. Os benefícios parecem diminuir à medida que o tamanho do arquivo aumenta (tentado com seq 10M, 15s para sed, 5s para ed). Boas dicas de qualquer maneira (+1).
Mat
A partir da versão 3.15, o Linux agora possui uma API para recolher partes de um arquivo em sistemas de arquivos baseados em alguma extensão, mas pelo menos para o ext4 que só pode ser feito em blocos completos (geralmente 4k).
Stéphane Chazelas
Mesmo que a edição exija reescrever o arquivo inteiro, às vezes é muito útil ter ferramentas de linha de comando para editar com eficiência. No meu caso, isso ajudou quando tive que remover a primeira linha de um arquivo que era maior que a RAM total do sistema.
Jason
3

O método mais eficiente, não faça isso! Se você precisar, em qualquer caso, precisará do dobro do espaço "grande" no disco e desperdiçará IO.

Se você estiver preso com um arquivo grande que deseja ler sem a 1ª linha, aguarde até precisar lê-lo para remover a 1ª linha. Se você precisar enviar o arquivo de stdin para um programa, use tail para fazer isso:

tail -n +2 | your_program

Quando você precisar ler o arquivo, poderá aproveitar a oportunidade para remover a 1ª linha, mas apenas se tiver o espaço necessário no disco:

tail -n +2 | tee large_file2 | your_program

Se você não consegue ler do stdin, use um fifo:

mkfifo large_file_wo_1st_line
tail -n +2 large_file > large_file_wo_1st_line&
your_program -i large_file_wo_1st_line

ainda melhor se você estiver usando o bash, aproveite a substituição do processo:

your_program -i <(tail -n +2 large_file)

Se você precisar procurar no arquivo, não vejo uma solução melhor do que não ficar preso ao arquivo em primeiro lugar. Se este arquivo foi gerado pelo stdout:

large_file_generator | tail -n +2 > large_file

Caso contrário, sempre há a solução de substituição de processo ou processo:

mkfifo large_file_with_1st_file
large_file_generator -o large_file_with_1st_file&
tail -n +2 large_file_with_1st_file > large_file_wo_1st_file

large_file_generator -o >(tail -n 2+ > large_file_wo_1st_file)
jfg956
fonte
1

Você pode usar o Vim no modo Ex:

ex -sc '1d|x' large_file
  1. 1 selecione a primeira linha

  2. d excluir

  3. x salvar e fechar

Steven Penny
fonte
0

Isso é apenas teorização, mas ...

Um sistema de arquivos personalizado (implementado usando o FUSE ou um mecanismo similar) pode expor um diretório cujo conteúdo é exatamente o mesmo que um diretório já existente em outro lugar, mas com os arquivos truncados conforme desejado. O sistema de arquivos converteria todos os deslocamentos de arquivos. Então você não precisaria reescrever um arquivo demorado.

Mas, como essa idéia não é trivial, a menos que você tenha dezenas de terabytes desses arquivos, implementar esse sistema de arquivos seria muito caro / demorado para ser prático.

liori
fonte