ack使い方メモ

※2010/4/18 パイプを使った例 を追記しました


先々週くらいから、vim上からackを使った「ディレクトリ以下のファイル一括置換」を行うvimスクリプト書いたりしてました。
でもなんかしっくりこないので公開するかどうかは微妙…


ちなみにackは簡単に言うと「find+grep」を一発実行するようなものです。
ハイライトなども対応しているし、他のコマンドに結果をパイプして渡したりするのにも使えるので
激しく便利。


で、そのためにいろいろack調査してたのですが、
日本語の説明があまりなかったので使い方などをメモ書きしておきます。
ちなみに、以下の実行例についてはplaggerのソースを検索した結果になっています。



インストール

cpan App::Ack
でok。
yumとかapt-getでもパッケージあるようですし、単一スクリプトとしても提供されているようです。
詳しくはこちらのHow To Install Ackをご参照下さい。

基本的な使い方

ack パターンマッチ [ファイル名(省略可)]

ex)カレントディレクトリ以下から decode_content というサブルーチンを検索

ack decode_content 

実行結果*1

assets/plugins/Filter-FindEnclosures/ustream.pl
2:use Plagger::Util qw( decode_content );

assets/plugins/Filter-FindEnclosures/youtube.pl
2:use Plagger::Util qw( decode_content );
25:            $args->{content} = decode_content($res);

lib/Plagger/FeedParser.pm
46:        $content  = Plagger::Util::decode_content($res);

...

ファイル絞り込みに関するオプション*2

-f

パターン検索しないで対象ファイルのみ出力*3
ex)カレントディレクトリ以下から perlファイルの一覧を表示

ack -f --perl 

実行結果

assets/plugins/CustomFeed-Script/dave-trailer-HD.pl
assets/plugins/CustomFeed-Script/domain-expire.pl
assets/plugins/CustomFeed-Script/jp-playstation-store.pl

...
-a

すべてのファイルタイプを検索対象にする*4

--perl

perlファイルのみ対象。
他に指定出来るファイルタイプについては 「ack --help-types」の実行結果をご参照下さい。

-G regex

対象ファイル名のパターンを指定(正規表現)。
ex)カレントディレクトリ以下から パス名が「"/Filter/"」に一致するファイルから、
 decode_content というサブルーチンを検索

ack decode_content -G /Filter/

実行結果

lib/Plagger/Plugin/Filter/EntryFullText.pm
11:use Plagger::Util qw( decode_content );
115:    $args->{content} = decode_content($res);

lib/Plagger/Plugin/Filter/FindEnclosures.pm
6:use Plagger::Util qw( decode_content );
187:    return decode_content($res);

パターンマッチに関するオプション

-w

単語の完全マッチ

-i

大文字小文字を区別しない



出力結果に関するオプション

-l

パターンマッチしたファイル名のみ出力
ex)

ack decode_content -l

実行結果

assets/plugins/Filter-FindEnclosures/ustream.pl
assets/plugins/Filter-FindEnclosures/youtube.pl
lib/Plagger/FeedParser.pm
lib/Plagger/Plugin/CustomFeed/2chSearch.pm
lib/Plagger/Plugin/CustomFeed/BloglinesCitations.pm
lib/Plagger/Plugin/CustomFeed/GoogleNews.pm
lib/Plagger/Plugin/CustomFeed/MixiDiarySearch.pm
lib/Plagger/Plugin/CustomFeed/PerlMonks.pm
lib/Plagger/Plugin/CustomFeed/Simple.pm
lib/Plagger/Plugin/Filter/EntryFullText.pm
lib/Plagger/Plugin/Filter/FindEnclosures.pm
lib/Plagger/Plugin/Summary/TrackbackRDF.pm
lib/Plagger/Util.pm
-C

ヒットした行の前後表示行数を指定

ex)マッチした前後5行を表示

ack -C 5 decode_content 

実行結果

assets/plugins/Filter-FindEnclosures/ustream.pl
1-# author: yappo, typester
2:use Plagger::Util qw( decode_content );
3-
4-sub handle {
5-    my ($self, $url) = @_;
6-    $url =~ qr!http://(?:www.)?ustream.tv/recorded/.+!;
7-}

assets/plugins/Filter-FindEnclosures/youtube.pl
1-# author: mizzy
2:use Plagger::Util qw( decode_content );
3-
4-sub handle {
5-    my ($self, $url) = @_;
6-    $url =~ qr!http://(?:(?:au|br|ca|fr|de|us|hk|ie|it|jp|mx|nl|nz|pl|es|tw|gb|www)\.)?youtube\.com/(?:watch(?:\.php)?)?\?v=.+!;
7-}
--

...
--nogroup

「--noheading」と「--nobreak」を指定したのと同じ表示(見た目の変更)
ちなみにデフォルトは--groupを指定した表示になっている。

ex)

ack decode_content --nogroup

実行結果

assets/plugins/Filter-FindEnclosures/ustream.pl:2:use Plagger::Util qw( decode_content );
assets/plugins/Filter-FindEnclosures/youtube.pl:2:use Plagger::Util qw( decode_content );
assets/plugins/Filter-FindEnclosures/youtube.pl:25:            $args->{content} = decode_content($res);
lib/Plagger/FeedParser.pm:46:        $content  = Plagger::Util::decode_content($res);
lib/Plagger/Plugin/CustomFeed/2chSearch.pm:8:use Plagger::Util qw( decode_content );
lib/Plagger/Plugin/CustomFeed/2chSearch.pm:43:    my $content = decode_content($res);
lib/Plagger/Plugin/CustomFeed/BloglinesCitations.pm:7:use Plagger::Util qw( decode_content );
lib/Plagger/Plugin/CustomFeed/BloglinesCitations.pm:42:    my $content = decode_content($res);
lib/Plagger/Plugin/CustomFeed/GoogleNews.pm:49:    my $content = Plagger::Util::decode_content($res);
...
--pager

好きなページャを指定できる
ex)

ack decode_content --pager="less"

.ackrcファイル

これを$HOMEディレクトリに作っておくと、オプションを自動で付与してくれる。
(ex)

--ignore-dir=tmp
--sort-files
--pager=less
--nogroup
--type-add=ruby=.rake,rakefile,Rakefile,.builder
--type-set=tags=tags

2010/4/18追記 パイプを使った一例

(ex)カレントディレクトリ以下のperlファイルの全てに対し、「this」を「that」に一括置換する

ack -f --perl | xargs perl -p -i -e's/this/that/g'

(ex)カレントディレクトリ以下の「Hoge」にマッチしたファイルの全てに対し、「Hoge」を「Fuga」に一括置換する

ack Hoge -l | xargs perl -pi -e 's/Hoge/Fuga/g'

ドキュメント

ここで紹介したものはごく一部ですので、
より詳しい使い方を知りたい方は公式ドキュメントをご参照下さい。
http://betterthangrep.com/
http://search.cpan.org/dist/ack/ack-base

*1:この検索結果をベースとして、他オプションの実行結果と見比べてみて下さい

*2:何もしなくても .svn やblib などのディレクトリは自動で除外

*3:というかこのオプションが有効な時はパターン指定できない

*4:これデフォルト?