みんな、grep(1)
ってめんどくさくない?検索なんて頻繁にやるのに4文字も打たないといけないし、.svn
とかCVS
とかバックアップファイルの除外が簡単にできないし、OSによるがディレクトリを指定するとディレクトリエントリを対象にしてくれたりする。おまけに正規表現なんてExtended Regexpがデフォルトでいいのに、そうするにはegrep
とさらに1文字タイプしないといけない。しかも、grep pattern
と打ってしばらく経つのに何も出てこないと思ったら、こいつが待っているのは俺の入力!
ほんとあほらしいよね!というわけでお届けするのがgrep(1)
のラッパー、その名は「g」。特長と機能は以下です。
- 名前が1文字。よく使うものは短い名前に。ページャは
p
、エディタはe
、検索はg
。ハフマンの法則。 - ほぼ透過的に動作し、
grep(1)
の挙動を保つ。-E
がデフォルトなので正確にはegrep(1)
のラッパーとも言えるが、-F
を付けても「egrep: conflicting matchers specified
」などとバカみたいに怒られたりしない。 -
rsync --cvs-exclude
と同じファイル除外ルールを適用する。「grep -r pattern . | fgrep -v /.svn/
」のような(単純に考えて倍の時間が掛かるような)無駄は省こう。ちなみに、GNU grepのパターン指定フラグはディレクトリには適用されないので--exclude=.svn
は効かない。やるなら--exclude='*.svn-base'
くらいか。なお、g
でなく別の名前で呼ぶと全ファイルが対象になる。私は「ln g g!
」しています。 - ディレクトリを指定すればその下を再帰的に検索。(
grep -r
相当) - ファイル名を指定せず、標準入力が端末の場合はカレントディレクトリ以下を検索。端末からの入力を検索したい珍しいケースでは「
cat | g ...
」などとする。 - SUSv3 (POSIX) grep, GNU grepのオプションを理解、すべて
grep(1)
に丸投げ。ただし、実装上の都合でロングオプションは「--include '*.pl'
」ではなく「--include='*.pl'
」と一続きで書かないと理解しない。 - 実装は
sh(1)
で、内部的にfind(1)
とawk(1)
を呼ぶ。いずれもSUSv3準拠ならほぼいけるはずだが、以下の要件がある。- 関数
local
がSUSv3にはない。外しても動くので、sh(1)
が同関数をサポートしない環境では外すか、ksh(1), ash(1), bash(1)
などを使う。 - 空白等の入ったファイル名を正しく扱うため、
find(1)
に-print0
を、xargs(1)
には-0
を指定している。これらをサポートしない環境では、冒頭のフラグ定義の部分を調整する。
- 関数
最近はackなどを使う人もいると思うけど、シンプルなのを好むならどうぞ。Zshを使っているなら、.zshrc
に「compdef _grep g g!
」などと入れると良い。
追記1: GNU findだと--
が理解されないので、修正しました。(0.1.0 -> 0.1.1)
追記2: 空白等が入ったファイル名を正しく扱う修正を入れました。(0.1.1 -> 0.1.2)
追記3: 空白等が入ったパターンを正しく扱う修正を入れました。(0.1.2 -> 0.2.0)
Thank you for your sharing. I am worried that I lack creative ideas. It is your article that makes me full of hope. Thank you. But, I have a question, can you help me?