Tại sao egrep [wW] [oO] [rR] [dD] nhanh hơn từ grep -i?


49

Tôi đã sử dụng grep -ithường xuyên hơn và tôi phát hiện ra rằng nó chậm hơn so với egreptương đương, trong đó tôi khớp với chữ hoa hoặc chữ thường của mỗi chữ cái:

$ time grep -iq "thats" testfile

real    0m0.041s
user    0m0.038s
sys     0m0.003s
$ time egrep -q "[tT][hH][aA][tT][sS]" testfile

real    0m0.010s
user    0m0.003s
sys     0m0.006s

grep -ilàm xét nghiệm bổ sung mà egrepkhông?


12
Hãy thử grepcách khác, để đảm bảo bạn không đo được sự khác biệt giữa bộ nhớ đệm đĩa của flie.
EightBitTony

3
Tôi đã grep'd tập tin trước khi thử nghiệm, vì vậy nó được lưu trữ. Hầu như cùng một lúc nếu được thực hiện theo thứ tự ngược lại.
tildearrow

21
Điều này có thể phụ thuộc vào miền địa phương: một số địa phương liên quan đến các tính toán phức tạp để giải thích cho trường hợp không nhạy cảm. GNU grep đặc biệt chậm trong nhiều tình huống liên quan đến Unicode. Bạn đã sử dụng cài đặt ngôn ngữ nào? Theo biến thể Unix nào? Nội dung của tập tin thử nghiệm của bạn là gì?
Gilles 'SO- ngừng trở nên xấu xa'

6
@Gilles có vẻ tốt, lặp lại mỗi bài kiểm tra ở đây 100 lần (tính thời gian cho toàn bộ sự việc), egrepnhanh hơn grepcho đến khi tôi đặt LANG=Cvà sau đó cả hai đều giống nhau.
EightBitTony

2
@EightBitTony Nhìn vào userthời gian (không bao gồm thời gian chờ đĩa). Có một thứ tự cường độ khác nhau.
kasperd 15/03/2016

Câu trả lời:


70

grep -i 'a'tương đương với grep '[Aa]'ngôn ngữ chỉ có ASCII. Trong ngôn ngữ Unicode, các tương đương và chuyển đổi ký tự có thể phức tạp, do đó grepcó thể phải thực hiện thêm công việc để xác định các ký tự tương đương. Cài đặt ngôn ngữ liên quan là LC_CTYPE, xác định cách các byte được hiểu là các ký tự.

Theo kinh nghiệm của tôi, GNU grepcó thể bị chậm khi được gọi trong miền địa phương UTF-8. Nếu bạn biết rằng bạn chỉ tìm kiếm các ký tự ASCII, việc gọi nó trong ngôn ngữ chỉ ASCII có thể nhanh hơn. tôi mong đợi rằng

time LC_ALL=C grep -iq "thats" testfile
time LC_ALL=C egrep -q "[tT][hH][aA][tT][sS]" testfile

sẽ sản xuất thời gian không thể phân biệt.

Điều đó đang được nói, tôi không thể tái tạo phát hiện của bạn với GNU greptrên Debian jessie (nhưng bạn không chỉ định tệp thử nghiệm của mình). Nếu tôi đặt miền địa phương ASCII ( LC_ALL=C), grep -isẽ nhanh hơn. Các hiệu ứng phụ thuộc vào bản chất chính xác của chuỗi, ví dụ một chuỗi có các ký tự lặp lại làm giảm hiệu suất ( đó là điều được mong đợi ).


Tác giả sử dụng Ubuntu 14.04 đi kèm với grep 2.10. Tốc độ của các kết hợp không phân biệt chữ hoa chữ thường ( -i) với các vị trí đa bào nên được cải thiện trong 2,17 .
Lekensteyn

@Lekensteyn Rất tốt để biết, cảm ơn. Ubuntu 14.04 thực sự đi kèm với grep 2.16, nhưng đó cũng là trước 2.17; Tôi đã thử nghiệm với grep 2.20, điều này giải thích tại sao tôi không thấy sự chậm lại tương tự.
Gilles 'SO- đừng trở nên xấu xa'

Đúng, tôi đã xem xét bản phát hành LTS sai, Ubuntu 12.04 xuất xưởng với grep 2.10 trong khi Ubuntu 14.04 bao gồm grep 2.16.
Lekensteyn

1
Tôi khá chắc chắn rằng grep -i 'a'nó tương đương với grep '[Aa]'bất kỳ địa phương nào. Ví dụ đúng là grep -i 'i'đó là một trong hai grep '[Ii]'hoặc grep '[İi]'(chữ hoa tôi với dấu chấm ở trên, U + 130, Thổ Nhĩ Kỳ locale). Tuy nhiên, không có cách hiệu quả grepđể tìm lớp tương đương này với một miền địa phương.
MSalters

15

Vì tò mò, tôi đã thử nghiệm điều này trên hệ thống Arch Linux:

$ uname -r
4.4.5-1-ARCH
$ df -h .
Filesystem      Size  Used Avail Use% Mounted on
tmpfs           3.9G  720K  3.9G   1% /tmp
$ dd if=/dev/urandom bs=1M count=1K | base64 > foo
$ df -h .                                         
Filesystem      Size  Used Avail Use% Mounted on
tmpfs           3.9G  1.4G  2.6G  35% /tmp
$ for i in {1..100}; do /usr/bin/time -f '%e' -ao grep.log grep -iq foobar foo; done
$ for i in {1..100}; do /usr/bin/time -f '%e' -ao egrep.log egrep -q '[fF][oO][oO][bB][aA][rR]' foo; done

$ grep --version
grep (GNU grep) 2.23
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Written by Mike Haertel and others, see <http://git.sv.gnu.org/cgit/grep.git/tree/AUTHORS>.

Và sau đó một số thống kê lịch sự của Có cách nào để lấy min, max, trung vị và trung bình của một danh sách các số trong một lệnh không? :

$ R -q -e "x <- read.csv('grep.log', header = F); summary(x); sd(x[ , 1])"
> x <- read.csv('grep.log', header = F); summary(x); sd(x[ , 1])
       V1       
 Min.   :1.330  
 1st Qu.:1.347  
 Median :1.360  
 Mean   :1.362  
 3rd Qu.:1.370  
 Max.   :1.440  
[1] 0.02322725
> 
> 
$ R -q -e "x <- read.csv('egrep.log', header = F); summary(x); sd(x[ , 1])"
> x <- read.csv('egrep.log', header = F); summary(x); sd(x[ , 1])
       V1       
 Min.   :1.330  
 1st Qu.:1.340  
 Median :1.360  
 Mean   :1.365  
 3rd Qu.:1.380  
 Max.   :1.430  
[1] 0.02320288
> 
> 

Tôi đang ở en_GB.utf8địa phương, nhưng thời gian gần như không thể phân biệt được.

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.