เป็นไปได้ในทุบตีเพื่อเริ่มอ่านไฟล์จากการนับไบต์ arbitary นับ?


22

ฉันต้องการค้นหาวันที่ซึ่งอยู่ในบันทึก 8 GB (ข้อความ)

ฉันสามารถข้ามการอ่านตามลำดับแบบเต็มได้หรือไม่และทำการแยกไบนารีของไฟล์ (ขนาด) หรือทำการสำรวจระบบไฟล์inodes(ซึ่งฉันรู้น้อยมาก ) เพื่อเริ่มอ่านจากจุดแยกแต่ละจุดจนกว่าฉันจะหาออฟเซ็ตที่เหมาะสมจาก จะเริ่มค้นหาข้อความเพื่อหาบรรทัดที่กำหนดวันที่ได้ที่ไหน

tailการอ่านบรรทัดสุดท้ายไม่ได้ใช้การอ่านตามลำดับปกติดังนั้นฉันจึงสงสัยว่าสถานที่นี้มีให้บริการอย่างใดอย่างหนึ่งในทุบตีหรือฉันจะต้องใช้ Python หรือ C / C ++ ... แต่ฉันสนใจเฉพาะตัวbashเลือก ..


คำตอบ:


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

ซึ่ง .. สร้างไฟล์ที่ไม่มีการแบ่งชั่วคราวข้ามบล็อก * 512MB ของข้อมูลในแต่ละการทำงานอ่าน 64 ไบต์จากตำแหน่งนั้นและ จำกัด การส่งออกไปที่บรรทัดแรกของ 64 ไบต์

คุณอาจต้องการปรับ 64 เป็นสิ่งที่คุณคิดว่าคุณต้องการ


@akira .. มันดูดีจริงๆ แต่ฉันอยากจะดูอีกสักหน่อยก่อน .. (ดังนั้นจนกระทั่งพรุ่งนี้ .....
Peter.O

1
@akira .. 'dd' ยอดเยี่ยม มันทำงานได้ดีกับการค้นหาแบบแยกส่วนแบบไบนารี ... ตอนนี้ฉันสามารถแยก regex'd บรรทัด (โดยใช้ปุ่มวันที่) จากไฟล์ 8G ที่จัดเรียงในเวลาไม่ถึง 1 วินาที ... ดังนั้นดูเหมือนว่าฉันจะได้รับ 3 เป้าหมายส่วนบุคคลที่สองสำหรับการแยกช่วงของวันที่ระหว่างสองปุ่ม (รวม) .. ไม่รวมเวลาส่งออกซึ่งแตกต่างกันไปขึ้นอยู่กับว่าจะเอาท์พุทเท่าไร .. ฉันจะใช้ddมันเช่นกัน ... มันเป็นเครื่องมือที่ยอดเยี่ยม! :)
Peter.O

30

ดูเหมือนคุณต้องการ:

tail -c +1048576

หรือจำนวนไบต์ที่คุณต้องการข้าม เครื่องหมายบวกบอกหางให้วัดจากจุดเริ่มต้นของไฟล์แทนการสิ้นสุด หากคุณใช้หางรุ่น GNU คุณสามารถเขียนเป็น:

tail -c +1M

หากต้องการรับจำนวนไบต์คงที่หลังการตัดแทนที่จะเหลือส่วนที่เหลือทั้งหมดของไฟล์เพียงไพพ์ผ่านหัว:

tail -c +1048576 | head -c 1024

ความยืดหยุ่นของ Linux / bash นั้นยอดเยี่ยม (ฉันใช้เวลานานเกินไปในการสลับเป็น Linux) ฉันเพิ่งยอมรับคำตอบของอากิระ แต่ฉันก็ดึงมันจนกระทั่งฉันประเมินได้อย่างเต็มที่ ddข้ามไปยังไบต์ที่ระบุ (เช่นเดียวกับtail) แต่มันเป็นความเจ็บปวดที่เขียนโค้ดรอบความยาวบรรทัดที่ไม่รู้จักและจากนั้นการเรียกให้กดเพื่อดึงเส้นบางส่วนที่นำออกไป ... ดูเหมือนหาง | หัวสามารถทำได้อย่างเจ็บปวด (เร็ว?) . ฉันไม่เข้าใจว่าหัวสามารถเปิดปิดก๊อกที่หางได้อย่างไร แต่ดูเหมือนว่า :) มันต้องเป็นกรณีของ: หากหัวหยุดรับสัญญาณหางจะหยุดส่ง (และหยุดอ่านเพิ่มเติม) พรุ่งนี้ต้องกลับ ..
Peter.O

@ fred.bear: tail/ headไม่สามารถคาดเดาความยาวบรรทัดได้เช่นกัน คุณต้องกระโดดไปที่ตำแหน่ง x และจากนั้นคุณสามารถมองซ้ายหรือขวาของ x \nสำหรับถัดไป ไม่สำคัญว่าโปรแกรมจะเรียกว่าอะไร ดังนั้นในทั้งสองกรณีคุณข้ามไปที่ x แล้วใช้headเพื่อค้นหาทางด้านขวาของบรรทัดถัดไป
akira

tail|headให้ความสามารถในการไม่ต้องกังวลเลยเกี่ยวกับddcount 's val = ด้วย 'dd' หากฉันไม่ได้รับข้อมูลที่เพียงพอนั่นคือ "เกม" ความยืดหยุ่นของความยาวเส้นโดยทั่วไปนั้นยอดเยี่ยม ฉันได้เขียนฟังก์ชั่นสำหรับ 'dd' ซึ่งส่งกลับบรรทัดเต็ม "ถัดไปใกล้ที่สุด" และออฟเซ็ต แต่ฉันต้องการหลีกเลี่ยงปัญหาความยาว ฉันได้ทดสอบหาง | หัวและตอนแรกมันทำงานได้ดี (เพื่อชดเชย = 100MB) แต่ช้าลงอย่างมากที่จะใช้เวลา 2 นาทีสำหรับการเข้าถึงหนึ่งครั้งที่ offset = 8GB (ฉันทำได้awkใน 1 นาที) ... มันเยี่ยมมาก สำหรับขนาดเล็กไฟล์เป็น .. ขอขอบคุณที่ทำให้ฉันตระหนักถึงคำสั่งผสมหาง / หัว :)
Peter.O

2

ฉันจะลองทำสิ่งนี้เพื่อแยกบันทึกเป็นส่วนย่อย 512MiB เพื่อการแยกวิเคราะห์ที่รวดเร็วยิ่งขึ้น

split <filename> -b 536870912

หากคุณกำลังมองหาไฟล์ดังต่อไปนี้จะได้ผล:

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

ใช้เอาต์พุตนั้นเพื่อกำหนดไฟล์ที่จะ grep สำหรับวันที่ของคุณ


ขอบคุณ แต่มันช้ากว่าการค้นหาตามลำดับ ดูความคิดเห็นของฉันที่นี่unix.stackexchange.com/questions/8121/ … (แทนที่จะเขียนสิ่งเดียวกันที่นี่อีกครั้ง)
Peter.O

โดยใช้ 'แยก' คุณสัมผัสทุกไบต์เดียวครั้งเดียว ถ้าคุณทำเช่นนั้นคุณก็สามารถ grep ทั้ง 8gb เช่นกัน
akira

@sifusam .. ฉันต้องการค้นหาแบบแยกไบนารี่ (ไม่ใช่แยกไฟล์) en.wikipedia.org/wiki/Binary_search_algorithm ... ดังนั้นจึงเป็นคำตอบที่ดีสำหรับคำถาม differnt :) ขอบคุณสำหรับการตอบกลับ .. +1 เพื่อให้คุณม้วน ....
Peter.O

0

นี่คือสคริปต์ของฉันฉันกำลังมองหาบรรทัดแรกเป็นเขตข้อมูลแรกที่ตรงกับหมายเลขของฉัน เส้นจะถูกจัดเรียงตามฟิลด์แรก ฉันใช้ dd เพื่อตรวจสอบบรรทัดแรกของบล็อกของ 128K จากนั้นฉันข้ามไปยังบล็อกและทำการค้นหา มันปรับปรุงประสิทธิภาพเป็นไฟล์มากกว่า 1M

ความคิดเห็นหรือการแก้ไขใด ๆ ที่มีความนิยม!

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

*แก้ไข* ** grep เป็นเร็วขึ้นมากและ แอ๊กชั่นที่ดียิ่งขึ้น

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.