Bash'da, bir arbitary byte count ofsetinden bir dosya okumaya başlamak mümkün müdür?


22

8 GB günlüğünde (metin) bir yerde bir tarih bulmak istiyorum.

Tam bir sıralı okumayı bir şekilde atlayabilir miyim ve önce uygun bir ofset bulana kadar her bir ayrılma noktasından okumaya başlamak için dosyanın ikili boyutunu (boyut) veya bir şekilde dosya sisteminde gezinmeyi inodes( çok az şey biliyorum ) tarihi içeren bir satır için metin aramam nerede başlatılır?

tailson satırın okunması normal bir sıralı okuma kullanmaz, bu yüzden bu tesis bir şekilde bash'de kullanılabilir mi, yoksa Python veya C / C ++ kullanmam gerekir mi ... ama özellikle bir bashseçenekle ilgileniyorum ..


Yanıtlar:


8
for (( block = 0; block < 16; block += 1 ))
do 
    echo $block; 
    dd if=INPUTFILE skip=$((block*512))MB bs=64 count=1 status=noxfer 2> /dev/null | \
        head -n 1
done

hangi .. geçici bölünmüş dosya oluşturmaz, blokları atlar * her çalıştırmada 512MB veri, bu konumdan 64 bayt okur ve çıkışı bu 64 baytın ilk satırına sınırlar.

64'ü ihtiyacınız olan her şeye göre ayarlamak isteyebilirsiniz.


@akira .. Bu gerçekten iyi görünüyor, ama önce biraz daha bakmak istiyorum .. (yani, yarına kadar .....
Peter.O

1
@akira .. 'dd' hayret verici. İkili bölünmüş arama ile iyi çalışır ... Şimdi 1 saniyenin altında sıralanmış bir 8G dosyasından bir regex'd satırı (Tarih anahtarına göre) ayıklayabilirim ... Yani 3'üme ulaşacağım gibi görünüyor iki anahtar (dahil) arasında bir tarih aralığının ayıklanması için ikinci kişisel hedef .. çıktı süresi hariç, ne kadar çıktı alındığına bağlı olarak değişir .. Bunun için de kullanacağım dd... Harika bir araçtır! :)
Peter.O

30

Kulağa istediğiniz gibi geliyor:

tail -c +1048576

veya atlamak istediğiniz bayt sayısı. Artı işareti kuyruğa dosyanın başından sonuna kadar ölçüm yapmasını söyler. Kuyruğun GNU sürümünü kullanıyorsanız şu şekilde yazabilirsiniz:

tail -c +1M

Kesimden sonra, dosyanın geri kalanının tamamı yerine sabit sayıda bayt elde etmek için, sadece başından geçirin:

tail -c +1048576 | head -c 1024

Linux / bash esnekliği hayret verici (kesinlikle Linux'a geçmek için çok uzun zaman harcadım). Akira'nın cevabını yeni kabul etmiştim, ama bunu daha iyi değerlendirene kadar çekmiştim. ddbelirli bir bayta atlar (olduğu gibi tail), ancak bilinmeyen çizgi uzunlukları etrafında bir kodlama ağrısı ve daha sonra önde gelen kısmi çizgileri çıkarmak için bir sed çağrısı ... Görünüşe göre kuyruk | kafa bunu acısız bir şekilde yapabilir (hızlı?) . Kafanın kuyruğa musluğu nasıl kapatabileceğini anlamıyorum, ama öyle görünüyor ki :) Bir durum böyle olmalı: Kafa almayı durdurursa, kuyruk göndermeyi durdurur (ve daha fazla okumayı durdurur). Yarın geri dönmeliyim.
Peter.O

@ fred.bear: tail/ headsatır uzunluklarını da kör edemez. x konumuna atlamak zorundasınız ve sonra sonraki için x'in sağına veya soluna bakabilirsiniz \n. programın adı ne önemli değil. bu nedenle, her iki durumda da x'e atlarsınız ve ardından headsatırın sonraki sonu için sağa bakmak için kullanılır .
akira

tail|headteklifler yeteneği endişe değil hiç ilgili dd= val 'ın sayılır. 'Dd' ile, yeterli veri almazsam, "oyun bitti". Arbitary line uzunluklarının esnekliği mükemmeldir. Ben "en yakın" tam satır ve ofset döndürür 'dd' için bir işlev yazdım, ama uzunluk sorunu önlemek için tercih ediyorum. Şimdi kuyruk | kafa test ettik, ve başlangıçta iyi (= 100MB ofset için), ancak ofset = 8GB ( 1 dakika içinde yapabilirsiniz) bir erişim için 2 dakika almak dramatik yavaşlar awk... yani harika için daha küçük dosyaya var .. :) kuyruk / baş açılan beni farkında için teşekkürler
Peter.O

2

Daha hızlı ayrıştırma için günlüğü 512MiB parçalarına bölmek için böyle bir şey denerdim.

split <filename> -b 536870912

Dosyayı arıyorsanız aşağıdakiler işe yarayacaktır:

for file in x* ; do
  echo $file
  head -n 1 $file
done

Tarihiniz için hangi dosyanın grepleneceğini belirlemek için bu çıktıyı kullanın.


Teşekkürler, ancak sıralı bir aramadan daha yavaştır. Burada Yorumlarımdan göz unix.stackexchange.com/questions/8121/... (ziyade yeniden yazma Burada da aynı şeyi)
Peter.O

'böl' kullanarak her bayta bir kez dokunursunuz. bunu yaparsanız, sadece 8GB'ı da grep olabilir.
akira

@sifusam .. İkili bir bölünmüş arama yapmak istiyorum (sadece dosyaları bölmek değil) en.wikipedia.org/wiki/Binary_search_algorithm ... bu yüzden farklı bir soru için iyi bir cevaptı :) .. Yanıtladığınız için teşekkürler .. Sizi yuvarlamak için +1 ...
Peter.O

0

İşte benim senaryom, ilk satır numaramı eşleşen ilk satır arıyorum. Çizgiler ilk alana göre sıralanır. 128K'lık blokların ilk satırını kontrol etmek için dd kullanıyorum, sonra bloğa atlayıp bir arama yapıyorum. Verimliliği artırmak dosya 1M üzerinde olduğunu.

Herhangi bir yorum veya düzeltme takdir!

#!/bin/bash

search=$1;
f=$2;

bs=128;

max=$( echo $(du $f | cut -f1)" / $bs" | bc );
block=$max;
for i in $(seq 0 $max); do
 n=$(dd bs=${bs}K skip=$i if=$f 2> /dev/null| head -2 | tail -1 | cut -f1)
 if [ $n -gt $search ]; then
  block=`expr $i - 1` 
  break;
 fi
done; 
dd bs=${bs}K skip=$block if=$f 2> /dev/null| tail -n +2 | awk -v search="$search" '$1==search{print;exit 1;};$1>search{exit 1;};';

* DÜZENLEME * ** grep çok daha hızlı ve daha iyi ack

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.