序章

ファイルまたはディレクトリ構造でテキストを検索する場合、LinuxおよびUnixライクなシステムには、役立つツールが多数あります。 これらの中で最も一般的なものの1つは、 grep です。これは、グローバル正規表現の印刷を表します。

grepを使用すると、任意のテキスト入力セット内で正規表現で表現できる任意のパターンを簡単に検索できます。 ただし、これは最速のツールではなく、最適化を行わずに汎用ツールとして作成されました。

特にソースコードを検索するために、ackと呼ばれるgrepに触発されたツールが発明されました。 Perlの正規表現を利用して、ソースコードでパターンを効率的に検索し、気にしない結果を含めないように注意します。

このガイドでは、ソースコードからパターンを選択するための強力なgrep置換としてackを使用する方法について説明します。 ackツールはPerlを使用できるすべてのプラットフォームで使用できますが、Ubuntu14.04サーバーでのユーティリティのデモを行います。

Ackをインストールします

開始するには、最初のステップは、ackツールをマシンにインストールすることです。

UbuntuまたはDebianマシンでは、これはデフォルトのリポジトリからユーティリティをインストールするのと同じくらい簡単です。 パッケージはack-grepと呼ばれます。

sudo apt-get update
sudo apt-get install ack-grep

実行可能ファイルもack-grepとしてインストールされるため、次のコマンドを入力して、ツールのコマンドライン使用でこれをackに短縮するようにシステムに指示できます。

sudo dpkg-divert --local --divert /usr/bin/ack --rename --add /usr/bin/ack-grep

これで、ツールはack-grepではなくackという名前に応答します。

他のシステムでackを使用することを計画している場合、インストール方法は異なる場合があります。 CPANのPerlモジュールはApp::Ackと呼ばれます。 他のLinuxディストリビューションでは、リポジトリ内のパッケージ名が異なる場合があります。

Ackが注意を払うもの

ackの実際の使用法に入る前に、それがgrepとどのように異なるか、およびackの領域内にあるファイルについて少し説明しましょう。

ackツールは、プログラムのソースコード内のテキストを検索するために特別に作成されました。 このため、ツールは特定のファイルを検索し、他のファイルを無視するように最適化されています。

たとえば、プロジェクトのディレクトリ構造を検索する場合、バージョン管理システムのリポジトリ階層を検索することはほとんどありません。 これには古いバージョンのファイルに関する情報が含まれており、多くの重複が発生する可能性があります。 Ackは、これが検索したい場所ではないことを認識しているため、これらのディレクトリを無視します。 これにより、より焦点を絞った結果が得られ、誤検知が少なくなります。

同様に、特定のテキストエディタで作成された一般的なバックアップファイルは無視されます。 また、Webファイル、画像、PDFファイルの「縮小」バージョンなど、ソースディレクトリに一般的に見られる非コーディングファイルの検索も試行されません。 これらすべてが、ほとんどすべての検索でより良い結果につながります。 実行中はいつでもこれらの設定を上書きできます。

ackのもう1つの機能は、さまざまな言語のソースファイルについて知っていることです。 ディレクトリ構造内のすべてのPythonファイルを検索するように依頼できます。 .pyで終わるすべてのファイルを返しますが、または次の行で始まるすべてのファイルを返します。

 #!  / path / to / python

これは、拡張子で識別されるファイルと、一般的な最初の行マジックナンバー呼び出しを使用してPythonインタープリターを呼び出すように指示されたファイルと一致します。

 #!  / path / to / interpreter / to / run

これにより、非常に異なる種類のファイルを関連するものとして分類する強力な方法が作成されます。 好みに合わせてグループを追加または変更することもできます。

環境を整える

ackの力を示す最良の方法は、ソースコードディレクトリでそれを使用することです。

幸い、GitHubなどの公開サイトからソースツリーを簡単に取得できます。 リポジトリをプルダウンできるようにgitをインストールします。

sudo apt-get install git

次に、プロジェクトを取得する必要があります。 neovimプロジェクトは、さまざまな種類のファイルが含まれているため、良い例です。 そのリポジトリをホームディレクトリに複製してみましょう。

cd ~
git clone https://github.com/neovim/neovim.git

それでは、そのディレクトリに移動して開始しましょう。

cd neovim

さまざまなファイルをチェックして、私たちが持っている多様性のアイデアを入手してください。

ls

BACKERS.md       CMakeLists.txt   Doxyfile   scripts      uncrustify.cfg
clint-files.txt  config           Makefile   src          vim-license.txt
clint.py         contrib          neovim.rb  test
cmake            CONTRIBUTING.md  README.md  third-party

その最上位ディレクトリには、マークダウンファイル、プレーンテキスト、Rubyファイル、Pythonファイルがあります。 そして、プロジェクトの主要部分はCで書かれています。

また、私たちの生活を楽にするためにいくつかのことを設定したいと思います。

結果がターミナルウィンドウよりも大きい場合は、出力をlessに直接パイプします。 これにより、出力が画面から制御不能にスクロールするのを防ぐことができます。

次のように入力してください。

echo '--pager=less -RFX' >> ~/.ackrc

これにより、ack構成ファイルが作成され、最初のデフォルト以外のオプションが追加されます。 出力をlessにパイプするように指示し、色付きの出力を表示してパスをインテリジェントに処理できるようにするオプションをいくつか使用します。

Ackによる簡単な検索

始めましょう。 まず、grepが検索するものとackが検索するものの違いを示します。

Grepは、ディレクトリ構造内のすべてのファイルで一致するものを検索します。 次のように入力すると、このプロジェクトのファイルの総数を確認できます。

find . | wc -l

566

この記事の執筆時点で、neovimプロジェクトには合計566個のファイルがあります。 ackが気にするファイルの数を調べるには、次のように入力します。

ack -f | wc -l

497

ご覧のとおり、何もせずに検索対象のファイルを約12% of削除しました。

このプロジェクトでパターン「restrict」が見つかったすべてのインスタンスを調べたいとしましょう。 次のように入力できます。

ack restrict

Doxyfile
1851:# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
1860:# code bases. Also note that the size of a graph can be further restricted by
1861:# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.

vim-license.txt
3:I)  There are no restrictions on distributing unmodified copies of Vim except
5:    unmodified parts of Vim, likewise unrestricted except that they must
. . .

ご覧のとおり、ackは、「restrict」のインスタンスを、一致が見つかったファイルで分割します。 さらに、正確な行番号が表示されます。

しかし、ご覧のとおり、一部のインスタンス(コピーしたサンプル部分のすべて)は、「restricted」や「restriction」などの「restrict」のバリエーションと一致しています。 「制限する」という言葉だけが必要な場合はどうなりますか?

-wフラグを使用して、単語の境界で囲まれたパターンのインスタンスを検索するように指示できます。 これにより、単語の他の時制がなくなります。

ack -w restrict

vim-license.txt
37:       add.  The changes and their license must not restrict others from

clint.py
107:      Specify a number 0-5 to restrict errors to certain verbosity levels.

src/nvim/fileio.c
6846:   * Allow nesting of autocommands, but restrict the depth, because it's
. . .

ご覧のとおり、結果は以前に見たバリエーションなしで「制限」のみを示しています。 出力ははるかに焦点が絞られています。

上記の結果は、さまざまな種類のファイルタイプで検出されていることに気付いたかもしれません。 1つはプレーンテキストファイルで、1つはPythonファイルにあり、Cソースファイルには複数のケースがあります。

Pythonファイルで見つかった結果のみを表示するようにackに指示する場合は、次のように入力することで簡単にこれを行うことができます。

ack -w --python restrict

clint.py
107:      Specify a number 0-5 to restrict errors to certain verbosity levels.

探していたファイルパターンを指定する必要はありませんでした。 他のファイルと一致せずに必要なタイプのファイルをキャッチするために、特別な正規表現を作成する必要はありません。 Ackは多くの一般的な言語のファイルを知っているだけで、名前でそれらを参照できます。

各言語のackが返すファイルを変更する方法と、後で独自の言語グループを定義する方法について説明します。

検索フォーカスの分析

非常に単純なフラグをいくつか追加することで、非常に幅広い結果から1つだけになりました。 結果をどれだけ絞り込んだかを正確に見てみましょう。

フラグ-chを使用できます。これは、「何件の一致が返されたか」を意味する単純なイディオムと考えることができます。 -cフラグ自体は、次のように、各ファイル内の一致する行の数のみを返すようにackに指示します。

ack -c restrict

Doxyfile:3
Makefile:0
uncrustify.cfg:0
.travis.yml:0
neovim.rb:0
vim-license.txt:5

これにより、一致するファイルがない場合でも、すべてのファイルに対して1行が返されます。

-hフラグ自体は、出力のファイル名プレフィックスを抑制し、結果がゼロのファイルを削除します。 一緒に、彼らは検索が一致した行の数を表す単一の数字を吐き出します:

ack -ch restrict

101

101件の結果から始めました。 単語の境界に注意を払うように言ったとき、これらの大部分を切り取りました。

ack -ch -w restrict

16

そしてもちろん、Pythonファイルのみを表示するように指定した場合、結果を1つの一致に絞り込みました。

ack -ch -w --python restrict

1

検索を絞り込んだだけでなく、言語制限を追加することで、実際に検索を高速化しました。 Ackは、要求した言語に基づいて結果を単純にフィルタリングするのではなく、検索する前にこれを実行して、無関係なファイルを検索する必要がないようにします。

これは、timeコマンドを使用して検索のタイミングを調整することで確認できます。

time ack -ch restrict

101

real	0m0.407s
user	0m0.363s
sys	    0m0.041s

次に、言語固有のサブセット検索を試してみましょう。

time ack -ch -w --python restrict

1

real	0m0.204s
user	0m0.175s
sys	    0m0.028s

2番目は大幅に高速です。

検索出力の変更

-cフラグと-hフラグを確認したときに、検索出力の変更についてはすでに少し説明しました。 必要な出力を形成するのに役立つ他の便利なフラグがあります。

たとえば、前に見たように、-cフラグは、各ファイルで一致パターンが見つかった行数を出力します。 以前は-hで変更しましたが、代わりに-lで変更することもできます。 これにより、一致が見つかったファイルの番号のみが返されます。

ack -cl restrict

Doxyfile:3
vim-license.txt:5
clint.py:1
test/unit/formatc.lua:1
src/nvim/main.c:4
src/nvim/ex_cmds.c:5
src/nvim/misc1.c:1
. . .

ご覧のとおり、「0」で終わるすべての行が出力から削除されています。

行内で一致が見つかったことをで確認したい場合は、--columnオプションを使用して、その情報も出力するようにackに指示できます。

 ack -w --column --pythonstrict
  clint.py  107: 31 :エラーを特定の詳細レベルに制限するには、0〜5の数値を指定します。 

与えられる2番目の番号は、一致の最初の文字が出現する列番号です。 一部のエディターでは、特定の行と列に移動できるため、これは非常に役立ちます。

たとえば、client.pyファイルをvimテキストエディタで開くと、107Gと入力して行に移動し、一致の正確な位置に移動できます。次に31|を押して列の位置に移動します。 この種の正確な配置は、特に大きな単語内で一般的な部分文字列を検索する場合に非常に役立ちます。

結果のコンテキストがさらに必要な場合は、一致が発生する前または後に行を出力するようにackに指示できます。 たとえば、Pythonファイルの「restrict」一致の前に5行を出力するには、次のように-Bフラグを使用できます。

 ack -w --python-B5制限
 102- output = vs7 103-デフォルトでは、出力はemacsの解析を容易にするようにフォーマットされています。  Visual Studio 104互換の出力(vs7)も使用できます。  他の形式はサポートされていません。 105- 106- verbose =#107:エラーを特定の詳細レベルに制限するには、0〜5の数値を指定します。 

-Aフラグを使用して、一致後のコンテキスト行数を指定できます。

 ack -w --python-A2制限
 107:エラーを特定の詳細レベルに制限するには、0〜5の数値を指定します。 108- 109- filter = -x、+ y、…

-Cフラグを使用して、一致の上下に数行を出力する汎用コンテキスト仕様を指定できます。 たとえば、いずれかの方向に3行のコンテキストを取得するには、次のように入力します。

 ack -w --python-C3制限
 104互換の出力(vs7)も使用できます。  他の形式はサポートされていません。 105- 106- verbose =#107:エラーを特定の詳細レベルに制限するには、0〜5の数値を指定します。 108- 109- filter = -x、+ y、…110-適用するカテゴリフィルターのコンマ区切りリストを指定します:のみ

一致するファイル自体を印刷する代わりに、一致するファイルだけを印刷するには、-fフラグを使用できます。

ack -f --python

clint.py
contrib/YouCompleteMe/ycm_extra_conf.py

同じことができますが、-gフラグを使用してファイル/ディレクトリ構造のパターンを指定することもできます。 たとえば、次のように入力することで、パスのどこかにパターン「log」を持つすべてのC言語ファイルを検索できます。

ack -g log --cc

src/nvim/log.h
src/nvim/log.c

ファイルタイプの操作

ファイルの種類でフィルタリングする方法の基本を見てきました。 次のように入力することで、C言語ファイルのみを表示するようにackに指示できます。

ack -f --cc

test/includes/pre/sys/stat.h
src/nvim/log.h
src/nvim/farsi.h
src/nvim/main.c
src/nvim/ex_cmds.c
src/nvim/os/channel.c
src/nvim/os/server.c
. . .

次のように入力すると、ackが認識しているすべての言語と、各カテゴリに関連付けられている拡張子とファイルのプロパティを確認できます。

ack --help-types

Usage: ack-grep [OPTION]... PATTERN [FILES OR DIRECTORIES]

The following is the list of filetypes supported by ack-grep.  You can
specify a file type with the --type=TYPE format, or the --TYPE
format.  For example, both --type=perl and --perl work.

Note that some extensions may appear in multiple types.  For example,
.pod files are both Perl and Parrot.

    --[no]actionscript .as .mxml
    --[no]ada          .ada .adb .ads
    --[no]asm          .asm .s
    --[no]asp          .asp
. . .

ご覧のとおり、これにより、各ファイルタイプに一致するパラメータが得られます。 タイプの前に「no」を付けることで、特定のカテゴリのファイルを除外するようにackに指示することもできます。

したがって、次のように入力することで、C言語ファイルの数を確認できます。

ack -f --cc | wc -l

191

そして、次のように入力することで、C以外の言語ファイルの数を確認するために逆の操作を行うことができます。

ack -f --nocc | wc -l

306

タイプの分類を変更したい場合はどうなりますか? たとえば、CSSファイルを探しているときに、.sass.scss、および.lessファイルを照合する場合はどうでしょうか。 これらはタイプ「sass」とタイプ「less」のカテゴリ内ですでに一致していることがわかりますが、必要に応じてCSSカテゴリに追加することもできます。

これを行うには、次の一般的な構文を使用できます。

 ack --type-add = TYPE:FILTER:ARGS 

--type-addコマンドは、指定されたTYPEの追加の一致ルールを追加します。 この場合のFILTERextであり、ファイル拡張子による一致を意味します。 次に、これらの追加の拡張機能を追加することを通知できます。

完全なコマンドは次のようになります。

ack --type-add=css:ext:sass,scss,less

ただし、これは現在のコマンド(検索を実行していない)にのみ適用されます。 次のように入力して検索を追加できます。

ack --type-add=css:ext:sass,scss,less -f --css

これにより、.css.sass.scss、および.lessで終わるファイルが返されます。 私たちのプロジェクトには、これらのファイルはありません。 いずれにせよ、このコマンドは現在のコマンドに対してのみ存在するため、あまり役に立ちません。 ~/.ackrcファイルに追加することで、これを永続的にすることができます。

echo "--type-add=css:ext:sass,less" >> ~/.ackrc

まったく新しいタイプを作成する場合は、代わりに--type-setオプションを使用します。 構文はまったく同じですが、唯一の違いは、存在しない型を定義するために使用されることです。

おそらくお気づきかもしれませんが、最初の構文仕様のTYPEは、単なるカテゴリ名です。 私たちが見たFILTERはファイル拡張子でしたが、他のフィルターを使用することもできます。

isフィルターを使用して、ファイル名を直接照合できます。 example.txtというファイルと一致するexampleというタイプを作成するには、これを~/.ackrcファイルに追加します。

--type-set=example:is:example.txt

matchフィルターを使用して、通常の正規表現との一致を定義することもできます。 たとえば、「。bashrc」ファイルと「.bash_profile」ファイルに一致する「bashcnf」というタイプを作成する場合は、次のように入力できます。

echo "--type-set=bashcnf:match:/.bash(rc|_profile)/" >> ~/.ackrc

結論

ご覧のとおり、ackはプログラミングソースコードを操作するための非常に柔軟なツールです。 Linux環境内でファイルを検索するためだけに使用している場合でも、ほとんどの場合、ackの機能を強化すると便利です。

ジャスティン・エリングウッド