ทำไม egrep [wW] [oO] [rR] [dD] เร็วกว่าคำว่า grep -i?


49

ฉันใช้grep -iบ่อยขึ้นและฉันพบว่ามันช้ากว่าของegrepที่ฉันเปรียบเทียบกับตัวพิมพ์ใหญ่หรือตัวพิมพ์เล็ก:

$ 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 -iทำแบบทดสอบเพิ่มเติมที่egrepไม่?


12
ลองgrepวิธีอื่น ๆ เพื่อให้แน่ใจว่าคุณไม่ได้วัดความแตกต่างระหว่างการแคชดิสก์ของตัว flie
EightBitTony

3
ฉันได้ grep'd ไฟล์ก่อนการทดสอบดังนั้นจึงถูกแคช เกือบจะเท่ากันถ้าทำในลำดับย้อนกลับ
tildearrow

21
สิ่งนี้สามารถขึ้นอยู่กับสถานที่เกิดเหตุ: สถานที่บางแห่งเกี่ยวข้องกับการคำนวณที่ซับซ้อนเพื่อบัญชีสำหรับกรณีตาย grep GNU นั้นช้ามากในหลาย ๆ สถานการณ์ที่เกี่ยวข้องกับ Unicode คุณใช้การตั้งค่าภาษาใด ภายใต้ตัวแปร Unix อะไร ไฟล์ทดสอบของคุณคืออะไร?
Gilles 'ดังนั้น - หยุดความชั่วร้าย'

6
@Gilles ดูดีทำซ้ำการทดสอบแต่ละที่นี่ 100 ครั้ง (เวลาสิ่งทั้งหมด) egrepจะเร็วกว่าgrepจนกว่าฉันจะตั้งค่าLANG=Cและจากนั้นพวกเขาทั้งสองประมาณเดียวกัน
EightBitTony

2
@EightBitTony ดูที่userเวลา (ซึ่งไม่รวมเวลาที่รอดิสก์) มีลำดับความสำคัญแตกต่างกัน
kasperd

คำตอบ:


70

grep -i 'a'เทียบเท่ากับgrep '[Aa]'โลแคลเฉพาะ ASCII ในโลแคล Unicode การเทียบอักขระและการแปลงอาจซับซ้อนดังนั้นgrepอาจต้องทำงานพิเศษเพื่อกำหนดว่าอักขระใดเทียบเท่า การตั้งค่าโลแคลที่เกี่ยวข้องคือLC_CTYPEซึ่งกำหนดวิธีการตีความไบต์เป็นอักขระ

จากประสบการณ์ของฉัน GNU grepอาจช้าเมื่อเรียกใช้ในโลแคล UTF-8 หากคุณรู้ว่าคุณกำลังค้นหาอักขระ ASCII เท่านั้นการเรียกใช้ในสถานที่ที่ใช้เฉพาะ ASCII อาจเร็วขึ้น ฉันคาดหวังว่า

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

จะสร้างการกำหนดเวลาที่แยกไม่ออก

ที่ถูกกล่าวว่าฉันไม่สามารถทำซ้ำการค้นพบของคุณกับ GNU grepใน Debian jessie (แต่คุณไม่ได้ระบุไฟล์ทดสอบของคุณ) หากฉันตั้งค่าตำแหน่งที่ตั้ง ASCII ( LC_ALL=C) grep -iจะเร็วขึ้น เอฟเฟกต์ขึ้นอยู่กับลักษณะที่แท้จริงของสตริงตัวอย่างเช่นสตริงที่มีอักขระซ้ำลดประสิทธิภาพ ( ซึ่งคาดว่าจะเกิดขึ้น )


ผู้เขียนใช้ Ubuntu 14.04 ซึ่งมาพร้อมกับ grep 2.10 ความเร็วของการแข่งขันกรณีตาย ( -i) กับสถานที่สัญลักษณ์ควรจะมีการปรับปรุงใน2.17
Lekensteyn

@Lekensteyn ดีใจที่ได้ทราบขอบคุณ Ubuntu 14.04 จริงมาพร้อมกับ grep 2.16 แต่นั่นก็เป็นรุ่นก่อนหน้า 2.17 ฉันทดสอบด้วย grep 2.20 ซึ่งอธิบายว่าทำไมฉันจึงไม่เห็นการชะลอตัวแบบเดียวกัน
Gilles 'หยุดความชั่วร้าย'

ใช่ฉันกำลังดูการเปิดตัว LTS ที่ไม่ถูกต้อง Ubuntu 12.04 มาพร้อมกับ grep 2.10 ในขณะที่ Ubuntu 14.04 รวมถึง grep 2.16
Lekensteyn

1
ฉันค่อนข้างแน่ใจว่าgrep -i 'a'เทียบเท่ากับgrep '[Aa]'ในสถานที่ใด ๆ ตัวอย่างที่เหมาะสมgrep -i 'i'คือตัวใดตัวหนึ่งgrep '[Ii]'หรือgrep '[İi]'(ตัวพิมพ์ใหญ่ I ที่มีจุดด้านบน, U + 130, โลแคลภาษาตุรกี) อย่างไรก็ตามไม่มีวิธีที่มีประสิทธิภาพสำหรับgrepการค้นหาคลาสความเท่าเทียมกันนี้ที่ให้สถานที่
MSalters

15

จากความอยากรู้ฉันทดสอบสิ่งนี้ในระบบ 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>.

แล้วสถิติความสุภาพของมีวิธีการรับ min, max, มัธยฐานและค่าเฉลี่ยของรายการตัวเลขในคำสั่งเดียวหรือไม่ :

$ 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
> 
> 

ฉันอยู่ในen_GB.utf8สถานที่ แต่เวลาเกือบจะแยกไม่ออก

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