为什么egrep [wW] [oO] [rR] [dD]比grep -i word快?


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的磁盘缓存之间的差异。
AugustBitTony

3
我在测试之前已将该文件grep'd,因此已将其缓存。如果按相反的顺序进行,则几乎相同的时间。
tildearrow

21
这可能取决于语言环境:某些语言环境涉及复杂的计算,以解决不区分大小写的问题。在涉及Unicode的许多情况下,GNU grep特别慢。您使用了什么语言环境设置?在什么Unix变体下?测试文件的内容是什么?
吉尔斯(Gillles)“所以-别再邪恶了”

6
@Gilles看起来不错,在这里将每个测试重复100次(对整个过程进行计时),egrepgrep我设置之前要快LANG=C,然后它们大致相同。
AugustBitTony

2
@EightBitTony看user时间(不包括等待磁盘的时间)。差异有一个数量级。
卡巴斯德,2016年

Answers:


70

grep -i 'a'等效grep '[Aa]'于纯ASCII语言环境。在Unicode语言环境中,字符等效和转换可能很复杂,因此grep可能需要做额外的工作才能确定哪些字符等效。相关的语言环境设置为LC_CTYPE,它确定如何将字节解释为字符。

以我的经验,grep在UTF-8语言环境中调用GNU时可能会很慢。如果您知道仅在搜索ASCII字符,则在仅ASCII的语言环境中调用它可能会更快。我希望

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

会产生难以区分的时间。

话虽这么说,但我无法grep在Debian jessie上使用GNU重现您的发现(但您未指定测试文件)。如果设置ASCII语言环境(LC_ALL=C),grep -i速度会更快。效果取决于字符串的确切性质,例如,具有重复字符的字符串会降低性能(这是可以预期的)。


作者使用随grep 2.10一起提供的Ubuntu 14.04。-i具有多字节语言环境的不区分大小写的match()的速度应在2.17中有所提高。
Lekensteyn '16

@Lekensteyn很高兴知道,谢谢。Ubuntu 14.04实际上附带了grep 2.16,但这也早于2.17。我使用grep 2.20进行了测试,这说明了为什么我没有看到同样的速度下降。
吉尔斯(Gillles)“所以-别再作恶了”

正确,我正在查看错误的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 '16

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区域设置中,但是时间几乎无法区分。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.