Sed kullanarak büyük dosyalar için verimli yerinde başlık kaldırma?


24

Aşağıdaki komutlar birkaç dakika sürebilir, dosya boyutuna bağlıdır. Daha verimli bir yöntem var mı?

sed -i 1d large_file 

Yanıtlar:


34

edBunun yerine deneyin :

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

Bu “büyük” yaklaşık 10 milyon satır veya daha fazla anlamına gelirse, daha iyi kullanım tail. Yerinde düzenleme yapamaz, ancak performansı bu affedilmez hale getirir:

tail -n +2 large_file > large_file.new

Düzen bir süre farklılıkları göstermek için:

( awkJaypal kodu aynı makinede yürütme süresine sahip olmak için eklendi (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

Durumunda tail, oldukça yapmak için zaman saymaya kalksanız hem ilk satırı kaldırmak ve yerine bigfile.txtsahip bigfile.new.
rozcietrzewiacz

@ rozcietrzewiacz, amacın doğru. Teşekkür ederim. Güncellenmiş.
Manatwork

Bu gerçekten havalı! Ben de aynısını yaptım awkve şu sonucu aldım -[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, kodunuzu alternatifler listesine ekledim. Makinemde daha hızlıydı. Garip, awkperformansının yakın olması bekleniyor sed. (Kendime not: Asla beklemeyin - test
etmeyin

Bu benim durumumdaki en iyi çözümdü: tail -n +2 bigfile.txt > bigfile.new && mv -f bigfile.new bigfile.txt;Birden fazla işlem tarafından kullanılan tek bir görev listesini takip etmek için kilitli tek bir dosya kullanıyorum. Ben ilk afiş eskiden ne ile başladı: sed -i 1d large_file . Dosyanın 1-2 saniye boyunca kilitlenmesine neden oluyordu. tail/mvAçılan neredeyse anında tamamlar. Teşekkür ederim!
Chris Adams

6

Bir dosyanın başındaki şeyleri etkin bir şekilde kaldırmanın bir yolu yoktur. Verilerin baştan kaldırılması tüm dosyanın yeniden yazılmasını gerektirir.

Bir dosyanın sonundan kesmek çok hızlı olabilir (işletim sistemi artık yalnızca kullanılmamış blokları temizleyerek dosya boyutu bilgisini ayarlamalıdır). Bir dosyanın başından kaldırmaya çalıştığınızda bu genellikle mümkün değildir.

Tam olarak bir bloğu / kapsamı kaldırırsanız teorik olarak "hızlı" olabilir, ancak bunun için sistem çağrıları yoktur, bu nedenle dosya sistemine özgü anlambilimden (varsa) güvenmeniz gerekir. (Ya da dosyanın ilk başlangıcını işaretlemek için birinci blok / kapsam dahilinde bir çeşit mahsuplaşma, sanırım. Bunu da hiç duymadım.)


Dosya çok büyükse, G / Ç ek yükünün, satır sonunu işlemek için gereken CPU ek yükünden (muhtemelen çok) daha büyük olması muhtemeldir.
Mat

Haklısın. Ancak, araçların dosya içeriğine erişme şekillerinde fark olabilir. En iyisi gerekmediğinde satır satır işlem yapmamak veya en azından gerekmediğinde satır satır satır okumak değildir.
Manatwork

2
Aradaki farkın sonuçlarınızda çok büyük olmasına şaşırdım ve buradaki dosya boyutuyla yeniden oluşturabilirim. Dosya boyutu da arttıkça faydaları azalmış gibi görünüyor (sıra 10M, sed için 15s, ed için 5s ile denendi). Yine de iyi ipuçları (+1).
Mat

3.15 sürümünden başlayarak, Linux bir dosya bölümlerini bir miktar tabanlı dosya sistemlerinde daraltmak için bir API'ye sahiptir , ancak en azından ext4 için yalnızca tam bloklarda (genellikle 4k) yapılabilir.
Stéphane Chazelas

Düzenleme tüm dosyanın yeniden yazılmasını gerektirse bile, verimli bir şekilde düzenlemek için komut satırı araçlarına sahip olmak bazen çok kullanışlıdır. Benim durumumda bu, toplam sistem RAM'imden daha büyük bir dosyanın ilk satırını kaldırmak zorunda kalmamda yardımcı oldu.
Jason

3

En verimli yöntem, yapma! Bunu yaparsanız, herhangi bir durumda, diskte iki 'büyük' ​​alana ihtiyacınız vardır ve IO'ları boşa harcarsınız.

İlk satır olmadan okumak istediğiniz büyük bir dosyaya sıkışmışsanız, ilk satırın kaldırılması için okumanız gerekene kadar bekleyin. Dosyayı stdin'den bir programa göndermeniz gerekirse, bunu yapmak için kuyruk kullanın:

tail -n +2 | your_program

Dosyayı okumanız gerektiğinde, 1. satırı kaldırma olanağınız olabilir, ancak yalnızca diskte gereken boş alan varsa:

tail -n +2 | tee large_file2 | your_program

Stdin'den okuyamıyorsanız, bir fifo kullanın:

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

bash kullanıyorsanız, işlem değişikliğinden yararlanın:

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

Dosyada arama yapmanız gerekiyorsa, ilk başta dosyaya takılmamaktan daha iyi bir çözüm göremiyorum. Bu dosya stdout tarafından oluşturulmuşsa:

large_file_generator | tail -n +2 > large_file

Aksi halde, her zaman fifo veya proses ikame çözümü vardır:

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)

1

Vim'i Ex modunda kullanabilirsiniz:

ex -sc '1d|x' large_file
  1. 1 ilk satırı seç

  2. d silmek

  3. x kaydet ve kapat


0

Bu sadece teori, ama ...

Özel bir dosya sistemi (FUSE veya benzeri bir mekanizma kullanılarak uygulanır), içeriği zaten başka bir yerde var olan bir dizinin aynısı, ancak istediğiniz gibi kesilmiş dosyaların bulunduğu bir dizini gösterebilir. Dosya sistemi tüm dosya ofsetlerini tercüme eder. Öyleyse, bir dosyanın zaman alıcı bir kısmını yeniden yazmanız gerekmez.

Ancak, bu fikrin önemsiz olmadığı göz önüne alındığında, bu tür dosyalardan onlarca terabaytınız olmadıkça, bu tür bir dosya sistemini uygulamak pratik olamayacak kadar pahalı / zaman alıcı olacaktır.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.