Có thể trong bash, để bắt đầu đọc một tệp từ phần bù byte tùy ý?


22

Tôi muốn tìm một ngày ở đâu đó trong nhật ký 8 GB (văn bản).

Tôi có thể phần nào bỏ qua việc đọc tuần tự đầy đủ và trước tiên thực hiện phân chia nhị phân của tệp (kích thước) hoặc bằng cách nào đó điều hướng hệ thống tệp inodes(mà tôi biết rất ít), để bắt đầu đọc từ mỗi điểm phân tách, cho đến khi tôi tìm thấy phần bù phù hợp từ nơi để bắt đầu tìm kiếm văn bản của tôi cho một dòng ghi ngày tháng?

tailĐọc dòng cuối cùng không sử dụng đọc tuần tự bình thường, vì vậy tôi tự hỏi liệu cơ sở này có sẵn bằng cách nào đó trong bash không, hoặc tôi sẽ cần sử dụng Python hoặc C / C ++ ... nhưng tôi đặc biệt quan tâm đến một bashtùy chọn ..


Câu trả lời:


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

trong đó .. không tạo các tệp phân chia tạm thời, bỏ qua các khối * 512 MB dữ liệu mỗi lần chạy, đọc 64 byte từ vị trí đó và giới hạn đầu ra ở dòng đầu tiên trong 64 byte đó.

bạn có thể muốn điều chỉnh 64 thành bất cứ điều gì bạn nghĩ bạn cần.


@akira .. Điều này có vẻ thực sự tốt, nhưng tôi muốn xem xét nó thêm một chút trước .. (vì vậy, cho đến ngày mai .....
Peter.O

1
@akira .. 'dd' là tuyệt vời. Nó hoạt động tốt với tìm kiếm phân chia nhị phân ... Bây giờ tôi có thể trích xuất một dòng regex'd (bằng khóa Ngày của nó), từ tệp 8G được sắp xếp trong dưới 1 giây ... Vì vậy, có vẻ như tôi sẽ đạt được 3 mục tiêu cá nhân thứ hai để trích xuất một phạm vi ngày giữa hai khóa (bao gồm) .. không bao gồm thời gian đầu ra, thay đổi tùy thuộc vào mức độ đầu ra .. Tôi cũng sẽ sử dụng ddcho điều đó ... Đây là một công cụ tuyệt vời! :)
Peter.O

30

Nghe có vẻ như bạn muốn:

tail -c +1048576

hoặc bất cứ số byte nào bạn muốn bỏ qua. Dấu cộng cho biết đuôi để đo từ đầu tệp thay vì kết thúc. Nếu bạn đang sử dụng phiên bản đuôi của GNU, bạn có thể viết như sau:

tail -c +1M

Để có được số byte cố định sau khi cắt, thay vì tất cả phần còn lại của tệp, chỉ cần đưa nó qua đầu:

tail -c +1048576 | head -c 1024

Tính linh hoạt của Linux / bash là tuyệt vời (tôi chắc chắn đã dành quá nhiều thời gian để chuyển sang Linux). Tôi vừa mới chấp nhận câu trả lời của akira, nhưng tôi đã rút ra điều đó cho đến khi tôi đánh giá điều này đầy đủ hơn. ddnhảy đến một byte cụ thể (như vậy tail), nhưng đó là một nỗi đau mã hóa xung quanh độ dài dòng không xác định, và sau đó là một lời kêu gọi để loại bỏ các dòng một phần hàng đầu ... Có vẻ như đuôi | đầu có thể làm điều đó không đau (nhanh như vậy?) . Tôi không hiểu làm thế nào đầu có thể tắt vòi trên đuôi, nhưng có vẻ như vậy :) Đó phải là một trường hợp: Nếu đầu dừng nhận, đuôi dừng gửi (và dừng đọc thêm). Phải đi .. trở lại vào ngày mai.
Peter.O

@ fred.bear: tail/ headkhông thể đoán mù chiều dài dòng là tốt. bạn phải nhảy đến vị trí x và sau đó bạn có thể nhìn sang trái hoặc phải của x cho lần tiếp theo \n. nó không quan trọng chương trình được gọi là gì. vì vậy, trong cả hai trường hợp, bạn nhảy đến x và sau đó sử dụng headđể nhìn sang bên phải cho phần cuối của dòng tiếp theo.
akira

tail|headcung cấp khả năng không quan tâm chút nào về ddsố lượng = val. Với 'dd', nếu tôi không lấy đủ dữ liệu, đó là "trò chơi kết thúc". Tính linh hoạt của độ dài đường tùy ý là rất lớn. Tôi đã viết một hàm cho 'dd' trả về dòng đầy đủ "gần nhất" và phần bù của nó, nhưng tôi muốn tránh vấn đề về độ dài. Bây giờ tôi đã thử nghiệm đuôi | đầu và ban đầu nó hoạt động tốt (để bù = 100MB), nhưng chậm lại đáng kể để mất 2 phút cho một lần truy cập ở offset = 8GB (tôi có thể làm awkđiều đó trong 1 phút) ... thật tuyệt cho tập tin nhỏ hơn .. Cảm ơn vì đã cho tôi biết về combo đuôi / đầu :)
Peter.O

2

Tôi sẽ thử một cái gì đó như thế này để chia nhật ký thành các đoạn 512MiB để phân tích cú pháp nhanh hơn.

split <filename> -b 536870912

Nếu bạn đang tìm kiếm các tập tin sau đây sẽ làm việc:

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

Sử dụng đầu ra đó để xác định tập tin nào sẽ grep cho ngày của bạn.


Cảm ơn, nhưng nó chậm hơn một tìm kiếm tuần tự. Hãy xem ý kiến ​​của tôi ở đây unix.stackexchange.com/questions/8121/ (chứ không phải viết lại điều tương tự ở đây)
Peter.O

bằng cách sử dụng 'split', bạn chạm vào từng byte một lần. nếu bạn làm điều đó, bạn cũng có thể grep toàn bộ 8gb.
akira

@sifusam .. Tôi muốn thực hiện tìm kiếm phân tách nhị phân (không chỉ phân tách các tệp) en.wikipedia.org/wiki/Binary_search_alacticm ... vì vậy đó là một câu trả lời tốt cho một câu hỏi khác biệt :) .. Cảm ơn vì đã trả lời .. +1 để giúp bạn lăn ....
Peter.O

0

Đây là kịch bản của tôi, tôi đang tìm dòng đầu tiên là trường đầu tiên khớp với số của tôi. Các dòng được sắp xếp theo trường đầu tiên. Tôi sử dụng dd để kiểm tra dòng đầu tiên của khối 128K, sau đó tôi nhảy đến khối và thực hiện tìm kiếm. Nó cải thiện hiệu quả là tập tin hơn 1M.

Bất kỳ bình luận hoặc chỉnh sửa được đánh giá cao!

#!/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 nhanh hơn nhiều và ack thậm chí còn tốt hơn

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.