10
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

あなたの知らないlocateの世界

Last updated at Posted at 2020-06-27

locate

ファイル名データベースからパターンに合うファイルパスを表示します。

$ whatis locate
locate (1)           - ファイル名データベースからパターンに合うものを表示する
$ locate --version
mlocate 0.26
$ Copyright (C) 2007 Red Hat, Inc. All rights reserved.
このソフトウェアは GPL v.2 に基づいて提供されています。
このプログラムは法律が許す範囲で無保証で提供されます。

locateのインストール

大抵のLinux ディストロにはデフォルトで入っています。
Archlinuxではmlocateパッケージをインストールすることで使えます。

$ sudo pacman -S mlocate

ファイルパスを高速検索する

$ locate some_keyword

some_keywordを含むパスを表示します。
私の環境では検索にかかる時間は、保存ハードウェアSSD上に29万件の登録があるデータベースで0.4秒くらい、保存ハードウェアHDD上に450万件の登録があるデータベースで13秒くらいです。

デフォルトでは/var/lib/mlocate/mlocate.dbから検索します。
dbファイルの作り方は後述するupdatedbに記述します。

locate オプション

$ locate --help
Usage: locate [OPTION]... [PATTERN]...
Search for entries in a mlocate database.

  -A, --all              only print entries that match all patterns
  -b, --basename         match only the base name of path names
  -c, --count            only print number of found entries
  -d, --database DBPATH  use DBPATH instead of default database (which is
                         /var/lib/mlocate/mlocate.db)
  -e, --existing         only print entries for currently existing files
  -L, --follow           follow trailing symbolic links when checking file
                         existence (default)
  -h, --help             print this help
  -i, --ignore-case      ignore case distinctions when matching patterns
  -l, --limit, -n LIMIT  limit output (or counting) to LIMIT entries
  -m, --mmap             ignored, for backward compatibility
  -P, --nofollow, -H     don't follow trailing symbolic links when checking file
                         existence
  -0, --null             separate entries with NUL on output
  -S, --statistics       don't search for entries, print statistics about each
                         used database
  -q, --quiet            report no error messages about reading databases
  -r, --regexp REGEXP    search for basic regexp REGEXP instead of patterns
      --regex            patterns are extended regexps
  -s, --stdio            ignored, for backward compatibility
  -V, --version          print version information
  -w, --wholename        match whole path name (default)

よく使うオプションを表に記載します。

オプション 役割
-c, --count マッチしたファイルの数だけを表示する。
-d, --database DBPATH デフォルトの/var/mlocate/mlocate.db以外のデータベースを検索する。
-e, --existing dbにあるけれども、実際のファイルシステム上に存在するファイルしか表示しない。
-i, --ignore-case 大文字小文字無視
-l, --limit, -n LIMIT 表示数をLIMIT件に抑える。
-r, --regexp REGEXP 正規表現で検索する
--regex REGEXP 拡張正規表現で検索する
-S, --statistics ファイル数、ディレクトリ数などの統計情報を表示する

異なるデータベースファイルから検索する

$ locate -d /var/lib/mlocate/mymlocate.db

でデフォルトの/var/lib/mlocate/mlocate.db以外のデータベースファイルから検索します。

複数のデータベースファイルから検索する

$ locate -d /var/lib/mlocate/mymlocate1.db -d /var/lib/mlocate/mymlocate2.db key_word

のように-dオプションを複数使います。

または

$ locate -d /var/lib/mlocate/mymlocate1.db:/var/lib/mlocate/mymlocate2.db key_word

のように複数のデータベースファイルをコロンで区切ります。

複数のデータベースファイルから検索する(環境変数を使う)

コロンによって区切られた検索するデータベースのリストを環境変数LOCATE_PATHとして指定しておくと、-dオプションをデフォルトで指定していることと同様に動作します。

$ export LOCATE_PATH='/var/lib/mlocate/mymlocate.db:/var/lib/mlocate/mlocate.db'
$ locate key_word

複数のデータベースファイルから検索するときはLOCATE_PATHにコロン区切りでdbファイルを列挙していきます。

LOCATE_PATHをディレクトリ以下全てのファイルとして指定する

LOCATE_PATHを/var/lib/mlocate以下全てのファイルとするシェルスクリプトを紹介します。

以前までtrsedを使う方法で/var/lib/mlocate以下のdbファイル名を結合していましたが、pasteコマンドを使うともっと簡単になります。
参考: シェルスクリプトの中でjoin()とsplit()相当の事をやる

$ export LOCATE_PATH=$(paste -sd: <(find /var/lib/mlocate -name '*.db'))
# OR
$ export LOCATE_PATH=$(find /var/lib/mlocate -name '*.db' | paste -sd: -)

pasteコマンドのオプション-sで列結合から行結合に変更し、-d :でコロンで結合します。
上のスクリプトはpasteコマンドにリダイレクション<を使ってfindの結果を流し込み、下のスクリプトはパイプを使ってpasteの標準入力-findの結果を流し込みます。
結果は同じなのでお好みで選んでください。

マルチプロセスでlocate検索する

locateコマンドは高速に(数ミリ秒以内)にファイルを検索してくれるので速さに対しては大抵満足いっているのですが、SSDではなくHDDに保存された400万件超のファイルパスを検索するときは検索に10秒以上かかっているのでイライラが溜まってきます。
検索に10秒かかってもlocateは古いコマンドなのでシングルスレッド動作です。いまどきシングルスレッドで動いているシステムは化石なので、スレッドを複数使って高速化を図りたいと自然に思うようになってきます。
大抵のLinuxディストロのデフォルトでマルチプロセスにコマンドを実行できる機能がついています。それがxargsコマンドです。
locateコマンドが検索するデータベースファイルが複数ある場合に限り、データベース一つ一つに対してxargslocateコマンドの検索先を振り分けてくれます。

$ find /var/lib/mlocate -name '*.db' | xargs -P2 -I@ locate -d @ 'some_keyword'

上のシェルスクリプトと同様にしてfind ...で見つけ出したdbファイル全てに対してxargsが並列にコマンドを実行してくれます。
xargsのオプション-P2で2スレッドで並列処理を実行します。実行環境のCPUのコア数、スレッド数を超えない数値を指定しましょう。 -P0で自動的に出来る限り多くのプロセスを同時に実行しようとします。(man xargsを読んでください。)
-I@で@の位置にfind...の結果、すなわちデータベースのパスを埋め込みます。
locateコマンドが'some_keyword'を含むパスをデータベースファイルから探して表示します。

シングル/マルチスレッド実行時間比較
$ # シングルスレッド
$ timeit locate -d $(find /var/lib/mlocate -name '*.db' | tr "\n" : | sed -e 's/:$//g') --regex 'usr.*\d+.*f'
0.35s user 0.02s system 97% cpu 0.378 total
0.35s user 0.01s system 99% cpu 0.363 total
0.37s user 0.00s system 99% cpu 0.375 total

$ # マルチスレッド
$ timeit find /var/lib/mlocate -name '*.db' | xargs -P2 -I@ locate -d @ --regex 'usr.*\d+.*f'
0.01s user 0.00s system 96% cpu 0.009 total
0.00s user 0.00s system 95% cpu 0.009 total
0.01s user 0.00s system 95% cpu 0.009 total

timeitコマンドは実行時間を3回計測する自作shell functionです。

timeit_function
#!/usr/bin/zsh
# shell scriptを3回実行し、実行時間を表示
# USAGE:
#   timeit [command] <args>
function timeit() {
    for i ($(seq 3)) time sh -c "$*" > /dev/null 2>&1
}

統計情報

検索データベースに登録したファイル数などを表示します。
-dオプションで統計情報を表示するデータベースを選択できます。
LOCATE_PATHに複数のデータベースがあればすべてのデータベースの情報を表示します。

$ locate -S
データベース /var/lib/mlocate/mlocate.db:
        95,256 辞書
        866,720 ファイル
        ファイル名に 91,967,343 バイト
        データベースに保存するのに 27,641,702 バイト使いました

正規表現で検索する

regexpは正規表現、regexオプションは拡張正規表現を使用して検索できます。

正規表現と拡張正規表現の違い

ERE BRE 用途 代替表現
unsupported OR 表現 I don’t know
+ unsupported 1文字以上の繰り返し {1,}
? unsupported 0 or 1文字 {,1}
() () グループ化
{n,m} {n,m} n文字以上、m文字以下の繰り返し

AND検索

$ locate --regex 'document.*gz'

documentの後にgzが含まれるファイルを検索します。

gzの後にdocumentが含まれるファイルは検索されないので、「documentかつgzが含まれるファイルを検索する」わけではありません。

OR検索

$ locate --regex 'document|gz'

documentまたはgzが含まれるファイルを検索します。

NOT検索

$ locate document | grep -v gz

locateオプションだけでできませんが、grep -vを併用することで、「documentは含まれるが、gzは含まれないファイル」の検索ができます。

updatedb

locateで検索するデータベースファイル(.db)を作成、更新します。
updatedbにより作成されるデータベースファイルは、ファイルパスのリスト情報が記されたバイナリファイルです。
大抵/var/lib/mlocate下に作成されるため、updatedbコマンドを使用するときはroot権限が必要です。

この記事ではupdatedbをroot権限で実行するとして、sudoコマンドは省略して記載します。

  • dbファイルを事前に作成しておかないと検索されません。
  • dbファイルを事前に更新しておかないと古いファイルが検索されます。
    • 例えばdbファイルを作成した後に/home/hoge/attatchment.tar.gzを作成すると、存在するはずの/home/hoge/attatchment.tar.gzが検索結果に出てきません。
    • 例えばdbファイルを作成した後に/home/hoge/document.txtを削除すると、消されて存在しなくなったはずの/home/hoge/document.txtが検索結果に出てきます。
$ whatis updatedb
updatedb (1)         - ファイル名データベースを更新する
$ updatedb --version
updatedb (mlocate) 0.26
Copyright (C) 2007 Red Hat, Inc. All rights reserved.
このソフトウェアは GPL v.2 に基づいて提供されています。

このプログラムは法律が許す範囲で無保証で提供されます。

updatedb オプション

$ updatedb --help
利用方法: updatedb [オプション]...
mlocate データベースを更新します。

  -f, --add-prunefs FS           同じ FS を除外する
  -n, --add-prunenames NAMES     同じ NAMES を除外する
  -e, --add-prunepaths PATHS     同じ PATHS を除外する
  -U, --database-root PATH       データベース中の保存するサブツリー (省略値 "/")
  -h, --help                     このヘルプを印刷する
  -o, --output FILE              更新するデータベース (省略値
                                 `/var/lib/mlocate/mlocate.db')
      --prune-bind-mounts FLAG   bind マウントを除外する (省略値 "no")
      --prunefs FS               データベースから除外するファイルシステム
      --prunenames NAMES         データベースから除外する辞書名
      --prunepaths PATHS         データベースから除外するパス
  -l, --require-visibility FLAG  ファイルを報告する前に可視性をチェックする
                                 (デフォルト値 "yes")
  -v, --verbose                  見つかったファイルのバスを印刷する
  -V, --version                  バージョン情報を印刷する

設定はファイル`/etc/updatedb.conf'
から読み込んだ値を省略値とします。

バグを https://pagure.io/mlocate へ報告してください。

マウントしたドライブの検索データベースを作成する

updatedbはmntしたドライブを使ってデータベースを作成しないので、 次のようにして別ドライブのパスをデータベースに含めます。
(Linux環境ではmntも含まれていましたが、Windosホストの仮想マシンでcronすると共有ドライブを/mntにマウントしたところがデータベースに含まれませんでした。システム管理者じゃないので詳しくはわからないのですがWindowsの共有ドライブ機能かレイドを組んでバックアップしていることが関係してそうです。)

$ updatedb -U /mnt/z --output /var/lib/mlocate/another.db

上のコマンドは/mnt/z以下のファイルを検索データベースを/var/lib/mlocate/another.dbに出力します。

更にlocate検索するときは-dオプションを使ってanother.dbを指定するか、LOCATE_PATHにanother.dbを含めます。

--outputを省略すると/var/lib/mlocate/mlocate.dbに出力されます。

cron

定期的にコマンドを実行するデーモンを立ち上げます。

$ whatis cron
cron (8)             - 予定されたコマンドを実行するデーモン...

先述の通り、locate検索前にupdatedbコマンドを打ってデータベースを最新の状態にしておかないと、存在するはずのパスが検索結果に出てこなかったり、過去に存在したファイルパスが検索結果に出てきてしまいます。
そのため、updatedbは定期的に実行しておく必要があり、大抵のLinuxディストリビューションではcronにより設定済みです。

まとめ

  • locateコマンドは高速ファイルパス検索コマンドです。
  • locate検索するときにはupdatedbコマンドにより検索データベースを作る前準備が必要です。
  • データベースコマンドは定期的に作成しておくべきで、cronデーモンを利用することが主流です。
10
9
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?