grep(1) のオプションを試していたら、 grep -q PATTERN が grep PATTERN や grep -s PATTERN に比べて劇的に速い場合があるのに気づいた。気になったので少し追ってみた。環境は Mac OSX Leopard (10.5.8) で grep --version は grep (GNU grep) 2.5.1 です。
テスト用に適当なファイルを作って、オプションをかえつつ grep してみる。
kyanny-macbook:2009-12-01 kyanny$ perl -le 'print q{0} x 1000 for 1 .. 1_000_000' > hoge
kyanny-macbook:2009-12-01 kyanny$ echo 1 >> hoge
kyanny-macbook:2009-12-01 kyanny$ time grep -c 0 hoge
1000000
real 0m21.224s
user 0m3.178s
sys 0m1.120s
kyanny-macbook:2009-12-01 kyanny$ time grep -s -c 0 hoge
1000000
real 0m22.163s
user 0m3.324s
sys 0m1.165s
kyanny-macbook:2009-12-01 kyanny$ time grep -q -c 0 hoge
real 0m0.134s
user 0m0.001s
sys 0m0.005s
- q だけ超速い。 man を読むと、
-q, --quiet, --silent
Quiet; do not write anything to standard output. Exit immediately with zero status if any
match is found, even if an error was detected. Also see the -s or --no-messages option.
-s, --no-messages
Suppress error messages about nonexistent or unreadable files. Portability note: unlike GNU
grep, traditional grep did not conform to POSIX.2, because traditional grep lacked a -q
option and its -s option behaved like GNU grep's -q option. Shell scripts intended to be
portable to traditional grep should avoid both -q and -s and should redirect output to
/dev/null instead.ということで、よく読めば「マッチしたらすぐに exit(0) するよ」って書いてあるんだけど華麗に読み飛ばして grep.c を読みにいってしまい、まぁ当然ながらそのようになっていた。
http://www.opensource.apple.com/source/grep/grep-24/grep/src/grep.c
-q オプションが指定されてると exit_on_match というフラグがセットされて、 grepbuf() の while ループの中で exit(0) してると。
じゃあ PATTERN にマッチするものがファイルの先頭じゃなくて末尾にあったらどうなの?と少し意地悪なことをやってみると、
kyanny-macbook:2009-12-01 kyanny$ time grep -c 1 hoge 1 real 0m21.952s user 0m3.073s sys 0m1.163s kyanny-macbook:2009-12-01 kyanny$ time grep -s -c 1 hoge 1 real 0m22.261s user 0m3.099s sys 0m1.163s kyanny-macbook:2009-12-01 kyanny$ time grep -q -c 1 hoge real 0m22.373s user 0m3.101s sys 0m1.158s
まぁ予想どおり全部同じくらい時間がかかると。で結果が何もでてこない grep -q に使いどころなんてあんのかよって話だけど、存在確認さえできればいいケース(具体例は思いつかない)では $? をみればマッチしたかどうかだけはわかるので、大量のでかいログファイルから何行か探したいけど全ファイル調べるのはコストが高いので -q で事前調査してマッチしたやつだけ詳細にパースする・・・とか考えたけど、結局マッチしなかった場合ってのはファイルのおしりまで読んじゃうわけなので意味ないな。。