Perché egrep [wW] [oO] [rR] [dD] è più veloce di grep -i word?


49

Ho usato grep -ipiù spesso e ho scoperto che è più lento del suo egrepequivalente, dove combatto contro le lettere maiuscole o minuscole di ogni lettera:

$ 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

Esegue grep -itest aggiuntivi che egrepnon lo fanno?


12
Prova il grepcontrario, per assicurarti di non misurare la differenza tra la memorizzazione nella cache del disco del flie.
EightBitTony

3
Ho verificato il file prima del test, quindi viene memorizzato nella cache. Quasi le stesse volte se fatto in ordine inverso.
Tildearrow,

21
Ciò può dipendere dalle impostazioni locali: alcune impostazioni locali comportano calcoli complessi per tenere conto dell'insensibilità ai casi. GNU grep è particolarmente lento in molte situazioni che coinvolgono Unicode. Quali impostazioni internazionali hai usato? Con quale variante Unix? Qual è il contenuto del tuo file di test?
Gilles 'SO- smetti di essere malvagio' il

6
@Gilles ha un bell'aspetto, ripetendo ogni test qui 100 volte (cronometrando l'intera cosa), egrepè più veloce di grepfino a quando non ho impostato LANG=Ce quindi sono all'incirca uguali.
EightBitTony

2
@EightBitTony Guarda l' userora (che non include il tempo di attesa del disco). C'è un ordine di grandezza nella differenza.
Kasperd,

Risposte:


70

grep -i 'a'è equivalente a grep '[Aa]'in una locale solo ASCII. In una locale Unicode, le equivalenze e le conversioni dei caratteri possono essere complesse, quindi greppotrebbe essere necessario un lavoro extra per determinare quali caratteri sono equivalenti. L'impostazione locale pertinente è LC_CTYPE, che determina come i byte vengono interpretati come caratteri.

Nella mia esperienza, GNU greppuò essere lento quando viene richiamato in una locale UTF-8. Se sai che stai cercando solo caratteri ASCII, invocarlo in una locale solo ASCII potrebbe essere più veloce. Me lo aspetto

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

produrrebbe tempi indistinguibili.

Detto questo, non riesco a riprodurre le tue scoperte con GNU grepsu Debian jessie (ma non hai specificato il tuo file di test). Se imposto un'impostazione internazionale ASCII ( LC_ALL=C), grep -iè più veloce. Gli effetti dipendono dalla natura esatta della stringa, ad esempio una stringa con caratteri ripetuti riduce le prestazioni ( che è prevedibile ).


L'autore usa Ubuntu 14.04 fornito con grep 2.10. La velocità delle corrispondenze maiuscole / minuscole ( -i) con i locali multibyte dovrebbe essere migliorata in 2.17 .
Lekensteyn,

@Lekensteyn Buono a sapersi, grazie. Ubuntu 14.04 in realtà viene fornito con grep 2.16, ma è anche pre-2.17; Ho provato con grep 2.20, il che spiega perché non ho visto lo stesso rallentamento.
Gilles 'SO-smetti di essere malvagio' il

Bene, stavo guardando la versione LTS sbagliata, Ubuntu 12.04 viene fornito con grep 2.10 mentre Ubuntu 14.04 include grep 2.16.
Lekensteyn,

1
Sono abbastanza certo che grep -i 'a'è equivalente a grep '[Aa]'in qualsiasi locale. L'esempio corretto è grep -i 'i'quale è grep '[Ii]'o grep '[İi]'(I maiuscola con punto sopra, U + 130, locale turco). Tuttavia, non esiste un modo efficace per greptrovare questa classe di equivalenza data una locale.
Salterio

15

Per curiosità, l'ho provato su un sistema 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>.

E poi alcune statistiche per gentile concessione di C'è un modo per ottenere il minimo, il massimo, la mediana e la media di un elenco di numeri in un singolo comando? :

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

Sono sul posto en_GB.utf8, ma i tempi sono quasi indistinguibili.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.