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
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.)
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:
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:
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.
tail
, eu prefiro contar o tempo para fazer tanto remover a primeira linha e substituirbigfile.txt
combigfile.new
.awk
e 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
awk
o desempenho estivesse mais próximosed
do. (Nota para mim mesma: nunca espera - de teste.)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. Atail/mv
combinação é concluída quase instantaneamente. Obrigado!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.)
fonte
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:
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:
Se você não consegue ler do stdin, use um fifo:
ainda melhor se você estiver usando o bash, aproveite a substituição do processo:
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:
Caso contrário, sempre há a solução de substituição de processo ou processo:
fonte
Você pode usar o Vim no modo Ex:
1
selecione a primeira linhad
excluirx
salvar e fecharfonte
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.
fonte