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.