ย้อนกลับ grepping


44

สมมติว่าฉันมีไฟล์ข้อความขนาดใหญ่จริงๆ (ประมาณ 10.000.000 บรรทัด) ฉันต้องการgrepมันจากตอนท้ายและบันทึกผลลัพธ์ลงในไฟล์ วิธีที่มีประสิทธิภาพที่สุดในการทำงานให้สำเร็จคืออะไร?


10
ใช้tacและgrepเพื่อให้บรรลุสิ่งที่คุณต้องการ
Valentin Bajrami

1
นอกจากโซลูชั่นที่ยอดเยี่ยมที่โพสต์แล้ว GNU grepยังมี--max-count (number)สวิตช์ที่ยกเลิกหลังจากการแข่งขันจำนวนหนึ่งซึ่งคุณอาจสนใจ
Ulrich Schwarz

@ val0x00ff คุณสามารถลองดูคำถามนี้ได้
ไหม

คุณรู้หรือไม่ว่าคุณจะได้รับความนิยมมากแค่ไหน? เมื่อคุณคิดว่า grep ของคุณจะพบ 3 บรรทัดให้เริ่ม grepping และย้อนกลับหลังจากนั้น
วอลเตอร์ A

คำตอบ:


46

โซลูชัน tac / grep

tac file | grep whatever

หรือมีประสิทธิภาพมากกว่านี้เล็กน้อย:

grep whatever < <(tac file)

เวลาที่มีไฟล์ 500MB:

real    0m1.225s
user    0m1.164s
sys     0m0.516s

โซลูชั่นsed / grep :

sed '1!G;h;$!d' | grep whatever

เวลาที่มีไฟล์ 500MB: ยกเลิกหลังจาก 10+ นาที

awk / grepโซลูชัน:

awk '{x[NR]=$0}END{while (NR) print x[NR--]}' file | grep whatever

เวลาที่มีไฟล์ 500MB:

real    0m5.626s
user    0m4.964s
sys     0m1.420s

perl / grepโซลูชัน:

perl -e 'print reverse <>' file | grep whatever

เวลาที่มีไฟล์ 500MB:

real    0m3.551s
user    0m3.104s
sys     0m1.036s

2
sed, awkและperl(ด้วยวิธีนี้) ไม่ได้ตกลงตั้งแต่พวกเขาอ่านไฟล์จากจุดเริ่มต้นที่จะไม่มีประสิทธิภาพมาก ฉันคิดว่านั่นtacเป็นสิ่งที่ถูกต้อง
vinc17

1
@ vinc17 ใช่แล้วสถิติเวลาชี้ไปที่สิ่งที่คุณพูด
ความโกลาหล

2
@ val0x00ff < <(tac filename)ควรเร็วเท่ากับไพพ์: ในทั้งสองกรณีคำสั่งจะทำงานแบบขนาน
vinc17

7
หากคุณต้องการประสิทธิภาพมันจะเป็นการดีกว่าถ้าคุณวางtacgrep หากคุณมีไฟล์บรรทัด 10,000,000 ไฟล์ที่มีเพียง 2 แมตช์tacจะต้องย้อนกลับ 2 บรรทัดไม่ใช่ 10m grepจะยังคงต้องผ่านทุกสิ่งอย่างใดอย่างหนึ่ง
แพทริค

3
หากคุณใส่tacหลังจากgrepนั้นก็จะถูกอ่านจากท่อและไม่สามารถหา ซึ่งจะทำให้มีประสิทธิภาพน้อยลง (หรือล้มเหลวอย่างสมบูรณ์) หากจำนวนบรรทัดที่พบมีขนาดใหญ่
jjanes

17

วิธีนี้อาจช่วย:

tac file_name | grep -e expression

3
tacคือคำสั่ง GNU ในระบบอื่น ๆ tail -rส่วนใหญ่คิดเป็น
Stéphane Chazelas

@ Stéphane: อย่างน้อยระบบ Unix บางระบบอาจtail -rถูก จำกัด จำนวนบรรทัดเพียงเล็กน้อยนี่อาจเป็นปัญหา
RedGrittyBrick

1
@RedGrittyBrick คุณมีข้อมูลอ้างอิงเกี่ยวกับเรื่องนั้นหรือคุณสามารถบอกได้ว่าระบบใดที่มีข้อ จำกัด ดังกล่าว
Stéphane Chazelas

@ StéphaneChazelas, ล้มเหลวด้วยtail -r /etc/passwd tail: invalid option -- 'r'ฉันใช้ coreutils-8.21-21.fc20.x86_64
Cristian Ciupitu

@CristianCiupitu ตามที่ฉันพูด GNU มีtac(และ GNU เท่านั้นที่มีแทค) มี Unices อื่น ๆ อีกtail -rมากมาย GNU tailไม่สนับสนุน-r
Stéphane Chazelas

10

คนนี้ออกจากทันทีที่พบคู่แรก:

 tac hugeproduction.log | grep -m1 WhatImLookingFor

ต่อไปนี้จะให้ 5 บรรทัดก่อนและหลังการแข่งขันสองครั้งแรก:

 tac hugeproduction.log | grep -m2 -A 5 -B 5 WhatImLookingFor

จำไว้ว่าอย่าใช้-i(ไม่คำนึงถึงขนาดตัวพิมพ์) เว้นแต่คุณจะต้องทำเช่นนั้นเพราะจะทำให้ grep ทำงานช้าลง

หากคุณทราบสตริงที่แน่นอนที่คุณต้องการให้พิจารณาfgrep(สตริงคงที่)

 tac hugeproduction.log | grep -F -m2 -A 5 -B 5 'ABC1234XYZ'

9

หากไฟล์มีขนาดใหญ่มากไม่สามารถใส่ในหน่วยความจำฉันจะใช้PerlกับโมดูลFile :: ReadBackwardsจากCPAN:

$ cat reverse-grep.pl
#!/usr/bin/perl

use strict;
use warnings;

use File::ReadBackwards;

my $pattern = shift;
my $rev = File::ReadBackwards->new(shift)
    or die "$!";

while (defined($_ = $rev->readline)) {
    print if /$pattern/;
}

$rev->close;

แล้ว:

$ ./reverse-grep.pl pattern file

ข้อดีของวิธีนี้คือคุณสามารถปรับแต่ง Perl เพื่อทำอะไรก็ได้ที่คุณต้องการ
zzapper

1
@zzapper: หน่วยความจำมันได้อย่างมีประสิทธิภาพอีกด้วยตั้งแต่เมื่อมันอ่านบรรทัดไฟล์โดยสายแทนของไฟล์ Slurp tacในหน่วยความจำเช่น
cuonglm

ทุกคนสามารถเพิ่มการสนับสนุน -m สำหรับสิ่งนี้? ฉันต้องการทดสอบไฟล์จริง ดู: gist.githubusercontent.com/ychaouche/…
ychaouche
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.