Apakah mungkin dalam bash, untuk mulai membaca file dari offset byte byte arbiter?


22

Saya ingin mencari tanggal yang berada di suatu tempat dalam log 8 GB (teks).

Dapatkah saya agak bypass sequential read penuh, dan pertama kali melakukan split biner dari file (ukuran), atau entah bagaimana menavigasi filesystem inodes(yang saya tahu sangat sedikit tentang), untuk mulai membaca dari setiap titik split, sampai aku menemukan yang cocok offset dari di mana harus memulai pencarian teks saya untuk baris yang memuat tanggal?

tailBacaan baris terakhir tidak menggunakan pembacaan berurutan normal, jadi saya ingin tahu apakah fasilitas ini entah bagaimana tersedia di bash, atau apakah saya perlu menggunakan Python atau C / C ++ ... tapi saya secara khusus tertarik pada bashopsi ..


Jawaban:


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

yang .. tidak membuat file temp-split, melompati blok * 512MB data pada setiap kali dijalankan, membaca 64 byte dari posisi itu dan membatasi output ke baris pertama dari 64 byte itu.

Anda mungkin ingin menyesuaikan 64 dengan apa pun yang Anda pikir Anda butuhkan.


@ Akira .. Ini terlihat sangat bagus, tapi saya ingin melihatnya sedikit lebih dulu .. (jadi, sampai besok .....
Peter.O

1
@ Akira .. 'dd' adalah awsome. Ini bekerja dengan baik dengan pencarian pemecahan biner ... Saya sekarang dapat mengekstrak garis regex'd (dengan tombol Date), dari file 8G yang diurutkan dalam waktu kurang dari 1 detik ... Jadi sepertinya saya akan mencapai 3 saya target pribadi kedua untuk mengekstraksi rentang tanggal antara dua kunci (inklusif) .. tidak termasuk waktu output, yang bervariasi tergantung pada berapa banyak yang dihasilkan .. Saya akan menggunakan dduntuk itu juga ... Ini adalah alat yang hebat! :)
Peter.O

30

Kedengarannya seperti yang Anda inginkan:

tail -c +1048576

atau berapa pun byte yang ingin Anda lewati. Tanda plus memberi tahu ekor untuk mengukur dari awal file bukan akhir. Jika Anda menggunakan ekor versi GNU Anda dapat menuliskannya sebagai:

tail -c +1M

Untuk mendapatkan jumlah byte yang tetap setelah dipotong, alih-alih semua sisa file, cukup pipa melalui kepala:

tail -c +1048576 | head -c 1024

Linux / fleksibilitas bash adalah awsome (saya pasti menghabiskan terlalu lama beralih ke Linux). Saya baru saja menerima jawaban akira, tetapi saya sudah menariknya sampai saya menilai ini sepenuhnya. ddmelompat ke byte tertentu (seperti halnya tail), tetapi itu adalah kode sakit di sekitar panjang garis yang tidak diketahui, dan kemudian panggilan untuk sed untuk melepaskan garis parsial terkemuka ... Sepertinya ekor | kepala dapat melakukan itu tanpa rasa sakit (secepat?) . Saya tidak mengerti bagaimana kepala dapat mematikan keran di ekor, tetapi tampaknya :) Ini harus menjadi kasus: Jika kepala berhenti menerima, ekor berhenti mengirim (dan berhenti membaca lebih lanjut). Harus pergi .. kembali besok.
Peter.O

@ fred.bear: tailSaya headtidak bisa membutakan tebak panjang garis juga. Anda harus melompat ke posisi x dan kemudian Anda dapat melihat ke kiri atau kanan x untuk selanjutnya \n. tidak masalah apa nama programnya. jadi, dalam kedua kasus Anda melompat ke x dan kemudian gunakan headuntuk melihat ke kanan untuk akhir baris berikutnya.
akira

tail|headmenawarkan kemampuan untuk tidak peduli sama sekali tentang dd's count = val. Dengan 'dd', jika saya tidak mengambil data yang cukup, itu "game over". Fleksibilitas panjang garis arbiter bagus. Saya telah menulis fungsi untuk 'dd' yang mengembalikan baris penuh "terdekat berikutnya" dan ofsetnya, tapi saya lebih suka menghindari masalah panjang. Saya sekarang telah menguji tail | head, dan awalnya berkinerja baik (untuk mengimbangi = 100MB), tetapi melambat secara dramatis untuk mengambil 2 menit untuk satu akses pada offset = 8GB (saya bisa awkdalam 1 menit) ... jadi itu bagus untuk file yang lebih kecil .. Terima kasih telah membuat saya mengetahui tentang combo ekor / kepala :)
Peter.O

2

Saya akan mencoba sesuatu seperti ini untuk memecah log menjadi potongan 512MiB untuk penguraian yang lebih cepat.

split <filename> -b 536870912

Jika Anda mencari file, yang berikut ini akan berfungsi:

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

Gunakan output itu untuk menentukan file mana yang akan diambil untuk kencan Anda.


Terima kasih, tetapi lebih lambat dari pencarian berurutan. Lihat komentar saya di sini unix.stackexchange.com/questions/8121/… (daripada menulis ulang hal yang sama di sini)
Peter.O

dengan menggunakan 'split' Anda menyentuh setiap byte satu kali. jika Anda melakukan itu, Anda hanya bisa menangkap seluruh 8gb juga.
akira

@sifusam .. Saya ingin melakukan pencarian biner split (bukan hanya membagi file) en.wikipedia.org/wiki/Binary_search_algorithm ... jadi itu jawaban yang bagus untuk pertanyaan yang berbeda :) .. Terima kasih telah menjawab .. +1 untuk membuat Anda berputar ....
Peter.O

0

Ini adalah skrip saya, saya mencari baris pertama sedang kolom pertama cocok dengan nomor saya. Garis diurutkan sesuai dengan bidang pertama. Saya menggunakan dd untuk memeriksa baris pertama blok 128K, lalu saya melompat ke blok dan melakukan pencarian. Ini meningkatkan efisiensi adalah file lebih dari 1M.

Setiap komentar atau koreksi sangat dihargai!

#!/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;};';

* EDIT * ** grep jauh lebih cepat dan ack lebih baik

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.