ITエンジニアのための勉強会・イベントレポート情報メディア

それゆけ!ターミナル部 第8回ファイル・ディレクトリの検索を爆速にしよう!
skill

それゆけ!ターミナル部 第8回
ファイル・ディレクトリの検索を爆速にしよう!

2017.01.26

 
  • このエントリーをはてなブックマークに追加

みなさんこんにちは!ターミナル部部長のタナカトモフミです。

本連載では意外と見落としがちな基本的な事柄からちょっとマニアックなテクニックまで、ターミナルを使いこなすための方法を若手エンジニアのタミ夫くんとシェルスキー先生と一緒に学んでいきます。

今回はターミナルを使った作業の中でも利用頻度が高いファイル検索用のコマンドを取り上げます。findやgrepコマンドの存在を知っていても、実は使いこなせていないという方も多いのではないでしょうか。基本に立ち返ってこれらのコマンドの活用法をしっかりと押さえておきましょう。また、ソースコードの検索に便利なag/ptコマンドについても紹介します。

タナカトモフミ

ターミナルでの作業も板についてきたタミ夫くん、シェルスキー先生に依頼された作業も手際よくこなせるようになってきたようです。

そういえば頼んでおいた例のデータは作れたかのう?

あーあれっスか。もち完璧っス。ちゃんとスクリプト書いたんで、いつでも出せますよー。

やるのう。ではそのスクリプトからいただこうかのう。

あれ?スクリプトがないなー。こんな感じの名前だったと思うんだけど、どのディレクトリに置いちゃったっけなー。

検索すればええじゃろ。ファイル名の一部だけでもわかれば探せるぞ。

その顔はまたなんか知ってるやつっスね。早く教えてくださいよー。

ファイルの探し方

ファイルを探すコマンドでよく使われるのは、findとgrepコマンドでしょう。まずはこの2つのコマンドを使ってファイル・ディレクトリの名前や、ファイルの中身から検索する方法をおさらいしましょう。

まずはfindコマンドの使い方を簡単におさらいします。findコマンドはファイルやディレクトリを見つけるためのコマンドです。ファイルやディレクトリなどの種類を指定したり、名前を指定して検索することができます。

# 現在のディレクトリ(ドットが現在のディレクトリを表します)以下の hoge という名前のディレクトリを探す
# -type では、f(ファイル)、d(ディレクトリ)といった種類を指定
# -name では、ファイル・ディレクトリの名前を指定
# -nmae '*hoge*' といった指定をすることで部分一致検索も可能
$ find . -type d -name hoge

その他にも絞り込みのオプションとしてファイルが持つ属性である、タイムスタンプ(作成、アクセス、更新)やサイズによる検索も可能です。必要に応じて「man find」を確認して使用しましょう。

続いてgrepコマンドを簡単におさらいします。grepコマンドはテキストファイルの中身に対して一致するものを探すコマンドです。

# ファイルを指定して指定したパターンに一致する行を出力する
$ grep [pattern] [file]

# hello.txt というファイル内の hello がマッチする行を探す
$ grep hello hello.txt
hello

# -R オプションを使用して、指定したディレクトリ以下のファイルを全て対象にして検索する
$ grep hello -R .

# -n オプションを使用して hello.txt の何行目が一致したのかを表示する
$ grep -n hello hello.txt
4:hello

# -H オプションを使用してファイル名を表示する
$ grep -Hn hello hello.txt
hello.txt:4:hello

# -i オプションで大文字小文字を無視(ignore)する
$ grep -Hn -i HELLO hello.txt
hello.txt:4:hello

ファイル名や行数の表示はワンライナーなど、他のツールと組み合わせて使用する際に便利なオプションです。覚えておきましょう。

メタデータ検索を使って爆速検索

find コマンドは実行されるたびに実際にファイルシステムを辿り検索を行うため、検索はそれほど早くありません。特にディレクトリツリーのトップを指定して検索すると時間がかかる処理になります。これに対して、事前にファイルの名前や中身から、検索用のデータベースを作成することで検索を高速化するツールがあります。

まずは locate コマンドを紹介します。locateコマンドは Mac OS Xだけでなく、LinuxなどのUNIX系のOSでも使用可能なツールです。Mac OS Xでは初めからインストールされていますが、locateコマンドを実行すると以下のエラーが表示されます。

$ locate hello

WARNING: The locate database (/var/db/locate.database) does not exist.
To create the database, run the following command:

  sudo launchctl load -w /System/Library/LaunchDaemons/com.apple.locate.plist

  Please be aware that the database can take some time to generate; once
  the database has been created, this message will no longer appear.

まずデータベースを作成する必要があります。メッセージに従って以下のコマンドを実行しましょう。

$ sudo launchctl load -w /System/Library/LaunchDaemons/com.apple.locate.plist

上記のコマンド実行後、データベースの作成が始まりますので、しばらく待つ必要があります。時間はファイルの数に依存しますが、数分間はかかります。

終わったかどうかを確認するには、locateがデータベースを作成しているプロセスをチェックするか、locateコマンドがエラーを返さなくなるまで待つと良いでしょう。

# エラーなく実行できれば完了(エラーの場合は初回と同じ表示になるので待つ)
$ locate hello.txt
/Users/tanacasino/tmp/hello.txt
/Users/tanacasino/tmp/hoge/hello.txt

実行時間は環境に大きく影響を受けますが、筆者の環境でホームディレクトリ検索をするとこれだけの差が出ました。基本的には locate コマンドの方が素早くファイルを検索できるでしょう。

$ time find ~ -type f -name 'hello.txt'
/Users/tanacasino/tmp/hello.txt
/Users/tanacasino/tmp/hoge/hello.txt

real    0m13.353s
user    0m0.353s
sys 0m9.566s


$ time locate hello.txt
/Users/tanacasino/tmp/hello.txt
/Users/tanacasino/tmp/hoge/hello.txt

real    0m0.521s
user    0m0.497s
sys 0m0.015s

続いて、Mac OSで使用できる mdfind というコマンドを紹介します。mdfind コマンドは、Spotlight機能と同じ検索データベースを使う検索コマンドです。ファイル名ではなく、ファイルの中身を読み取って作成されたデータベースを使用してくれるため、「こんな感じの内容だった気がする…」といううろ覚え検索にも対応できます。

# ターミナル部の原稿も簡単に検索できる
$ mdfind それゆけ!ターミナル部
/Users/tanacasino/ターミナル部/05/05-shell-one-line.txt
/Users/tanacasino/ターミナル部/06/06-customize-bash.txt
/Users/tanacasino/ターミナル部/07/07-bash-it.txt

デフォルトでは検索範囲が広いため、目的外のファイルが多く検索されてしまうことがあります。そういった場合には、「-onlyin」オプションを使って、特定のディレクトリ以下のファイルのみに絞り込むことができます。

$ mdfind -onlyin ~/ターミナル部 それゆけ!ターミナル部
/Users/tanacasino/ターミナル部/05/05-shell-one-line.txt
/Users/tanacasino/ターミナル部/06/06-customize-bash.txt
/Users/tanacasino/ターミナル部/07/07-bash-it.txt

その他のコマンドオプションは「man mdfind」で確認しておきましょう。

ソースコードの検索は ag/pt で爆速に

ソースコードの検索は grep コマンドではなく、ag (The Silver Searcher)や pt (The Platinum Searcher) といったツールを使うことが一般的になってきました。通常、ほとんどのソースコードは GitやSubversion、Mercurialといったバージョン管理システムで管理されています。agコマンドやptコマンドでは、バージョン管理システムで除外されているファイル(.gitignore、.hgignore)を検索対象から除外するなどありがたい機能を備えています。どちらも非常に高速で使いやすいツールになっていますので、試して気に入った方を使うと良いでしょう。

# ag(The Silver Searcher)のインストール
$ brew install the_silver_searcher

# pt(The Platinum Searcher)のインストール
$ brew install pt

ここではagコマンドの使い方を簡単に紹介します。agコマンドの使い方は非常に簡単です。デフォルトではパターンを指定するだけでカレントディレクトリ以下を対象に自動的に探索します。表示も該当行をファイル毎にまとめて表示してくれるので見やすいです。

$ ag hello
hello.txt
4:hello

hoge/hello.txt
1:Hello, World!
2:Hello, World!
3:Hello, World!

ただし、該当行をファイル毎にグループ化されると他のツールと連携が難しいため、グループ化を行わないオプションもあります。

$ ag --nogroup hello
hello.txt:4:hello
hoge/hello.txt:1:Hello, World!
hoge/hello.txt:2:Hello, World!
hoge/hello.txt:3:Hello, World!

大文字・小文字を無視するオプションはgrepコマンドと同じです。

$ ag --nogroup -i HELLO
hello.txt:4:hello
hoge/hello.txt:1:Hello, World!
hoge/hello.txt:2:Hello, World!
hoge/hello.txt:3:Hello, World!

検索対象をファイルの種類で絞り込むこともできます(--scala が種類の指定。指定可能な種類のリストはag --list-file-types コマンドで閲覧できます)。

$ ag --scala EpollEventLoop
framework/src/play-netty-server/src/main/scala/play/core/server/NettyServer.scala
19:import io.netty.channel.epoll.{ EpollEventLoopGroup, EpollServerSocketChannel }
78:      case Native => new EpollEventLoopGroup(threadCount, threadFactory)

デフォルトでも見やすい出力が得られたり、ソースコードの種類で絞り込みができるのはプログラマには嬉しい機能です。

ディレクトリ移動ももっと早く!

ここまで、ファイルやディレクトリを素早く探す方法を紹介してきました。最後に紹介するのは、ディレクトリに素早く移動するためのツール autojump です。

Homebrewでインストールし、前回紹介したBash-it を使って有効化します。

$ brew install autojump
==> Downloading https://homebrew.bintray.com/bottles/autojump-22.5.0.el_capitan.bottle.1.tar.gz
######################################################################## 100.0%
==> Pouring autojump-22.5.0.el_capitan.bottle.1.tar.gz
==> Caveats
Add the following line to your ~/.bash_profile or ~/.zshrc file (and remember
to source the file to update your current session):
 [ -f /usr/local/etc/profile.d/autojump.sh ] && . /usr/local/etc/profile.d/autojump.sh

If you use the Fish shell then add the following line to your ~/.config/fish/config.fish:
 [ -f /usr/local/share/autojump/autojump.fish ]; and source /usr/local/share/autojump/autojump.fish

zsh completion has been installed to:
 /usr/local/share/zsh/site-functions
==> Summary
/usr/local/Cellar/autojump/22.5.0: 20 files, 168.3K

$ bash-it enable plugin autojump
autojump enabled.
$ reload

autojumpをセットアップした状態で、ディレクトリ移動をすると、移動したディレクトリが履歴として蓄積されていきます。そして j コマンドを使うと、過去の履歴からもっともマッチするディレクトリに移動することができます。

$ cd ~/devel/src/github.com/git/git
$ cd ~
# 全く関係ない場所からでも、名前にもっとも近いディレクトリに移動できる
$ j git/git
~/devel/src/github.com/git/git

autojumpを使うことでターミナルを使えば使うほど、自分がよく使うディレクトリに素早く移動し作業を開始することができます。

まとめ

いやーあったあったこれっスわ〜。よかったー。

目的のファイルやディレクトリを探すのは基本じゃし、これぐらいは覚えておくべきじゃな。

そういえば、前に失くして諦めてもう一回書いた別のスクリプトも発見したんすよー。
君そこにいたのかー!みたいな。スッキリっス。

いやいや。そもそも大事なスクリプトを適当な場所に書き散らかすのはやめるんじゃ。整理整頓はあらゆる物事の基本じゃ。

タミ夫くんのようにファイルをどこに置いたか忘れてしまった場合に限らず、目的のソースコードや設定ファイルを探す場合など、ターミナルでファイルの検索を行いたい場面は多々あるはずです。目的のファイルを特定しないと作業を進められない場合はいかに素早くファイルを探すことができるかが作業効率にも直結します。今回紹介したコマンドの使い方をしっかりと覚えておき、素早く目的のファイルを見つけられるようにしましょう。

原稿: 株式会社ビズリーチ ターミナル部部長 タナカトモフミ

株式会社ビズリーチ所属。ScalaコードをVimで書く日々をおくる。たまにうっかりIntellij IDEAに浮気してしまう。社内のVim部とEmacs部を和解させ、ターミナル部に統合することに成功したが、社内はEclipse, Intellij IDEA, Sublime Text, Atomが主流のため、戦いは続く。

https://twitter.com/tanacasino

それゆけ!ターミナル部 第8回ファイル・ディレクトリの検索を爆速にしよう!

この記事はどうでしたか?

おすすめの記事

キャリアを考える

BACK TO TOP ∧

FOLLOW