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
grepflie의 디스크 캐싱 간의 차이를 측정하지 않도록 다른 방법으로 시도 하십시오.
EightBitTony

3
테스트하기 전에 파일을 grep 했으므로 캐시됩니다. 역순으로 수행하면 거의 같은 시간입니다.
tildearrow

21
로케일에 따라 달라질 수 있습니다. 일부 로케일은 대소 문자를 구분하지 않는 복잡한 계산을 포함합니다. GNU grep은 유니 코드와 관련된 많은 상황에서 특히 느립니다. 어떤 로케일 설정을 사용 했습니까? 어떤 유닉스 변종에서? 테스트 파일의 내용은 무엇입니까?
Gilles 'SO- 악한 중지'

6
@Gilles는 좋아 보입니다. 여기에서 각 테스트를 100 번 반복하면 (전체를 타이밍), 설정 할 egrep때보 다 빠르며 거의 동일합니다. grepLANG=C
EightBitTony

2
@EightBitTony user시간을 봅니다 (디스크 대기 시간은 포함되지 않음). 차수에는 차이가 있습니다.
kasperd

답변:


70

grep -i 'a'grep '[Aa]'ASCII 전용 로케일 과 동일합니다 . 유니 코드 로캘에서 문자 등가 및 변환은 복잡 할 수 있으므로 grep어떤 문자가 같은지 확인하려면 추가 작업이 필요할 수 있습니다. 관련 로케일 설정은입니다 LC_CTYPE. 이는 바이트가 문자로 해석되는 방식을 결정합니다.

내 경험상 grepUTF-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데비안 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으로 테스트했는데 왜 같은 속도가 느려지지 않았는지 설명합니다.
Gilles 'SO- 악마 그만해'

오른쪽, 잘못된 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

호기심으로 아치 리눅스 시스템에서 이것을 테스트했습니다.

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