Чому 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навпаки, щоб переконатися, що ви не вимірюєте різницю між кешуванням диска мухи.
ВісімBitTony

3
Я переглянув файл до тестування, тому він кешований. Майже в той же час, якщо робити це в зворотному порядку.
tildearrow

21
Це може залежати від місцевості: деякі локалі передбачають складні обчислення для врахування нечутливості випадку. GNU grep особливо повільний у багатьох ситуаціях, пов’язаних з Unicode. Які параметри локалі ви використовували? Під яким варіантом Unix? Який вміст вашого тестового файлу?
Жиль "ТАК - перестань бути злим"

6
@Gilles виглядає добре, повторюючи тут кожен тест 100 разів ( egrepпризначаючи весь час), швидше, ніж grepпоки я не встановлю, LANG=Cі вони обидва приблизно однакові.
ВісімBitTony

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 Добре знати, дякую. Ubuntu 14.04 насправді постачається з grep 2.16, але це теж до 2.17; Я тестував grep 2.20, що пояснює, чому я не бачив такого ж уповільнення.
Жил "ТАК - перестань бути злим"

Правильно, я дивився на неправильну версію LTS, Ubuntu 12.04 поставляється з grep 2.10, а Ubuntu 14.04 включає grep 2.16.
Лекенштейн

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

А потім кілька ввічливості: чи є спосіб отримати мінімум, макс, медіану та середнє число списку чисел в одній команді? :

$ 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локалі, але часи майже не відрізняються.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.