Đảo ngược


44

Giả sử, tôi có một tệp văn bản thực sự lớn (khoảng 10.000.000 dòng). Tôi cần grepnó từ cuối và lưu kết quả vào một tập tin. Cách hiệu quả nhất để hoàn thành nhiệm vụ là gì?


10
Sử dụng tacgrepđể đạt được những gì bạn muốn.
Valentin Bajrami

1
Ngoài các giải pháp tuyệt vời được đăng, GNU grepcòn có một --max-count (number)công tắc hủy bỏ sau một số trận đấu nhất định, điều này có thể thú vị với bạn.
Ulrich Schwarz

@ val0x00ff bạn có thể xem câu hỏi này không
c0rp

Bạn có biết bạn sẽ có bao nhiêu lượt truy cập? Khi bạn nghĩ grep của bạn sẽ tìm thấy 3 dòng, bắt đầu grepping và đảo ngược sau đó.
Walter A

Câu trả lời:


46

giải pháp tac / grep

tac file | grep whatever

Hoặc hiệu quả hơn một chút:

grep whatever < <(tac file)

Thời gian với tệp 500MB:

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

Giải pháp sed / grep :

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

Thời gian với tệp 500MB: Đã hủy sau hơn 10 phút.

Giải pháp awk / grep :

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

Thời gian với tệp 500MB:

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

Giải pháp perl / grep :

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

Thời gian với tệp 500MB:

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

2
sed, awkperl(với phương pháp này) không phải là OK vì họ đọc các tập tin ngay từ đầu, mà là rất hiệu quả. Tôi cho rằng điều tacđó đúng.
vinc17

1
@ vinc17 có, thống kê thời gian chỉ ra những gì bạn nói.
hỗn loạn

2
@ val0x00ff < <(tac filename)Cần nhanh như ống: trong cả hai trường hợp, các lệnh chạy song song.
vinc17

7
Nếu bạn đang đi cho hiệu quả, tốt hơn là đặt tacsau grep. Nếu bạn đã có một tệp dòng 10.000.000, chỉ với 2 kết quả khớp, tacsẽ chỉ phải đảo ngược 2 dòng chứ không phải 10m. grepdù sao đi nữa vẫn sẽ phải trải qua toàn bộ.
Patrick

3
Nếu bạn đặt tacsau grep, nó sẽ được đọc từ một đường ống và vì vậy không thể tìm kiếm. Điều đó sẽ làm cho nó kém hiệu quả hơn (hoặc thất bại hoàn toàn) nếu số lượng dòng tìm thấy lớn.
jjanes

17

Giải pháp này có thể giúp:

tac file_name | grep -e expression

3
taclà lệnh GNU. Trên hầu hết các hệ thống khác, tương đương là tail -r.
Stéphane Chazelas 23/07/14

@ Stéphane: Trên ít nhất một số hệ thống Unix, tail -rbị giới hạn ở một số lượng nhỏ dòng, đây có thể là một vấn đề.
RedGrittyBrick

1
@RedGrittyBrick, bạn có tham khảo nào về điều đó không, hoặc bạn có thể vui lòng cho biết hệ thống nào có giới hạn đó không?
Stéphane Chazelas 23/07/14

@ StéphaneChazelas, tail -r /etc/passwdthất bại với tail: invalid option -- 'r'. Tôi đang sử dụng coreutils-8.21-21.fc20.x86_64.
Cristian Ciupitu

@CristianCiupitu, như tôi đã nói, GNU có tac(và chỉ GNU có tac) mà nhiều Unice khác có tail -r. GNU tailkhông hỗ trợ-r
Stéphane Chazelas

10

Cái này thoát ra ngay khi nó tìm thấy trận đấu đầu tiên:

 tac hugeproduction.log | grep -m1 WhatImLookingFor

Dưới đây đưa ra 5 dòng trước và sau hai trận đấu đầu tiên:

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

Hãy nhớ không sử dụng -i(trường hợp không nhạy cảm) trừ khi bạn phải làm như vậy sẽ làm chậm grep.

Nếu bạn biết chính xác chuỗi bạn đang tìm thì hãy xem xét fgrep(Chuỗi cố định)

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

9

Nếu tệp thực sự lớn, không thể vừa trong bộ nhớ, tôi sẽ sử dụng Perlvới mô-đun File :: ReadBackwards từ 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;

Sau đó:

$ ./reverse-grep.pl pattern file

Ưu điểm của phương pháp này là bạn có thể điều chỉnh Perl để làm bất cứ điều gì bạn muốn.
zzapper

1
@zzapper: Đó cũng là bộ nhớ hiệu quả, vì khi nó đọc từng dòng tệp thay vì tệp slurp trong bộ nhớ như thế nào tac.
cuonglm

bất cứ ai có thể thêm một -m hỗ trợ cho việc này? Tôi muốn thử nghiệm trên các tập tin thực sự. Xem: gist.githubusercontent.com/ychaouche/ từ
ychaouche
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.