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反対の方法を試して、フライのディスクキャッシュの違いを測定していないことを確認してください。
EightBitTony

3
テストの前にファイルをgrepしたので、キャッシュされます。逆の順序で行われた場合、ほぼ同じ時間。
ティルダロー

21
これはロケールに依存する場合があります。一部のロケールでは、大文字と小文字を区別しない複雑な計算が必要になります。GNU grepは、Unicodeを含む多くの状況で特に遅くなります。どのロケール設定を使用しましたか?どのUnixバリアントの下で?テストファイルの内容は何ですか?
ジル 'SO-悪であるのをやめる'

6
@Gillesは見栄えがよく、各テストをここで100回繰り返す(全体のタイミングを調整する)ので、設定するegrepよりも速くなり、両方ともほぼ同じになります。grepLANG=C
EightBitTony

2
@EightBitTony user時間(ディスク待機時間を含まない)を確認します。違いには桁違いがあります。
カスペルド

回答:


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

区別できないタイミングを生成します。

そうは言っても、grepDebian jessie でGNUを使用してあなたの発見を再現することはできません(しかし、テストファイルを指定しませんでした)。ASCIIロケール(LC_ALL=C)を設定すると、grep -i高速になります。効果は、文字列の正確な性質に依存します。たとえば、文字が繰り返されると、パフォーマンスが低下します(これは予想されることです)。


著者はgrep 2.10に同梱されているUbuntu 14.04を使用しています。大文字と小文字を区別しない一致(-i)のマルチバイトロケールとの速度は、2.17で改善されているはずです。
-Lekensteyn

@Lekensteyn知っていただきありがとうございます、ありがとう。Ubuntu 14.04には実際にはgrep 2.16が付属していますが、これは2.17より前のものです。私はgrep 2.20でテストしました。これは、同じスローダウンが見られなかった理由を説明しています。
ジル 'SO-悪であるのをやめる'

右、私は間違ったLTSリリースを見ていました。Ubuntu12.04にはgrep 2.10が含まれていますが、Ubuntu 14.04にはgrep 2.16が含まれています。
-Lekensteyn

1
これはどのロケールでもgrep -i 'a'同等であると確信していgrep '[Aa]'ます。適切な例は、(上記のドット付きの大文字のI、U + 130、トルコ語ロケール)のgrep -i 'i'いずれgrep '[Ii]'grep '[İi]'です。ただし、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現地にいますが、時間はほとんど区別できません。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.