Быстрый поиск файла по имени - утилита locate

Как было сказано ранее find решает практически все задачи которые могут возникнуть у пользователя в связи с поиском и последующей обработкой нужных файлов или каталогов. Однако, довольно часто, возникают ситуации когда вам с одной стороны не нужна вся мощь find, а с другой хотелось чтобы поиск происходил побыстрее, и без значительной загрузки системы. Ведь запустив find с каким нибудь хитрым условием, да еще вызывающий внешние команды, да указав начать поиск с корневой директории, можно добиться того что система будет настолько загружена, что ваш системный администратор грешным делом подумает о визите кул хацкеров, но мы конечно не звери и нашего администратора пугать не будем. Поэтому для глобального поиска воспользуемся утилитой locate.

Использование locate

Данная утилита просто незаменима в случае если вам хотя бы приблизительно известно имя файла, который нужно найти. Отличительная особенность данной команды, скажем от того же find, в том что при работе она не сканирует по настоящему файловую систему, поиск идет в предварительно построенной базе, в которой хранится как-бы слепок с файловой системы. Такой слепок выполняется с помощью команды locate -u или updatedb, которая по настоящему перелопачивает ваши жесткие или сетевые диски, а имена всех найденных файлов записывает в базу. Естественно что данная процедура довольно ресурсоемкая, и может занимать довольно длительное время. Ее запуск обычно поручают crontab, который запускает updatedb с требуемой частотой. Частота обновления базы зависит от того насколько часто обновляется содержимое файловой системы, а также насколько важна актуальность данных. Так обычно обновление базы выполняется автоматически раз в неделю, или вручную, после того как вы или системный администратор установили новую партию свежего ПО. Отмечу, для того чтобы обновить базу, нужно иметь права суперпользователя.

Приведу простейший пример использования:

	$ locate traceroute
	/usr/man/man8/traceroute.8.gz
	/usr/sbin/traceroute6
	/usr/sbin/traceroute

	$ locate mpg123
	/usr/doc/mpg123-0.59r
	/usr/doc/mpg123-0.59r/BUGS
	/usr/doc/mpg123-0.59r/CHANGES
	/usr/doc/mpg123-0.59r/COPYING
	/usr/doc/mpg123-0.59r/INSTALL
	/usr/doc/mpg123-0.59r/JUKEBOX
	/usr/doc/mpg123-0.59r/README
	/usr/doc/mpg123-0.59r/TODO
	/usr/doc/mpg123-0.59r/mp3license
	/usr/man/man1/mpg123.1.gz
	/usr/bin/mpg123
	$

Из приведенных примеров видно три существенных момента, касающихся поведения locate. Во-первых ищутся все файлы и каталоги в именах которых встречается подстрока заданная в качестве аргумента. Во-вторых файлы выводятся включая полный путь к ним. В-третьих заданная подстрока вообще может не входить в имя самого файла, а встречаться в его пути. Так во втором примере в список найденных файлов было полностью включено содержимое каталога mpg123-0.59r.

Иногда требуется более точный поиск, когда нужно ограничить то место куда может входить заданная подстрока. Скажем если нам нужно найти только файлы и каталоги в название которых входит mpg123. В данном случае можно использовать шаблоны „аля bash“ (помните *, ?, [...]) или более продвинутый вариант использующий регулярные выражения. Я предпочитаю последний, как более мощный и продвинутый.

Для того чтобы сообщить locate что вы хотите использовать регулярные выражения, нужно указать форму locate -r. Так в нашем случае запрос будет выглядеть следующим образом:

	$ locate -r "mpg123[^/]*$"
	/usr/doc/mpg123-0.59r
	/usr/man/man1/mpg123.1.gz
	/usr/bin/mpg123
	$

Строка mpg123[^/]*$ - просит locate найти те файлы в которых после подстроки mpg123 могут быть ноль или более символов, кроме символа /, после чего идет конец строки. Таким образом из результата поиска исключаются строки вида /usr/doc/mpg123-0.59r/BUGS.

Еще одна полезная возможность - это форма вызова locate -i. Параметр -i говорит о том что нужно произвести нечувствительный к регистру поиск:

	$ locate  "/etc/dir"
	/usr/local/share/emacs/21.1/etc/dired-ref.ps
	/usr/local/share/emacs/21.1/etc/dired-ref.tex
	$ locate -i "/etc/dir"
	/usr/local/share/emacs/21.1/etc/dired-ref.ps
	/usr/local/share/emacs/21.1/etc/dired-ref.tex
	/etc/DIR_COLORS
	$

Использование совместно с другими командами

Сам по себе locate не выполняет ничего кроме вывода имен нужных файлов. Однако вы не всегда можете удовлетворится лишь созерцанием имен и месторасположения найденных файлов. Здесь вам на помощь приходят любимые трубопроводы, конвейеры и прочие радости командной строки.

К примеру хотим получить кроме самих файлов еще и информацию о атрибутах этих файлов. В данном случае нам на помощь приходит подстановка команд:

$ locate crontab
/usr/man/man1/crontab.1.gz
/usr/man/man5/anacrontab.5.gz
/usr/man/man5/crontab.5.gz
/usr/bin/crontab
/etc/anacrontab
/etc/crontab
$ ls -ld `!!`
ls -ld `locate crontab`
-rw-r--r--  1 root root     370 Mar  3  2000 /etc/anacrontab
-rw-r--r--  1 root root     255 Aug 27  1999 /etc/crontab
-rwsr-xr-x  1 root root   21816 Feb  3  2000 /usr/bin/crontab
-rw-r--r--  1 root root    1584 Feb  3  2000 /usr/man/man1/crontab.1.gz
-rw-r--r--  1 root root     669 Mar  3  2000 /usr/man/man5/anacrontab.5.gz
-rw-r--r--  1 root root    3495 Feb  3  2000 /usr/man/man5/crontab.5.gz
$

В данном примере первой командой мы получили список интересующих нас файлов, а второй передали этот список команде ls -ld, в результате чего получили чудный список с требуемой информацией. Кто забыл чего делает `!!` читать тут Работаем с историей команд. Параметр -d сообщает ls что вместо содержимого каталогов, выводить их атрибуты.

Способ с подстановкой подходит в том случае если у нас не много файлов. В противном случае мы можем столкнутся с ограничением на длину строки параметров передаваемых ls -l. К примеру:

	$ locate / | wc -l   # <--- locate - выводит все файлы в системе
	                     #      wc     - подсчитывает их количество
	70968
	$ ls -ld `locate /` | wc -l
	bash: /bin/ls: Argument list too long
	0
	$

Как видим вариант не прошел. Поэтому если ожидается большое количество файлов на выходе, более предпочтительнее будет воспользоваться утилитой xargs которая просто читает свой входной поток, разбивает его на строки, а потом эти строки небольшими порциями скармливает программе переданной ей в качестве параметра. Чтобы было более понятно приведу простой пример в котором видно что делает xargs:

	$ ls /usr/
	X11R6    etc                info      man
	bin      games              kerberos  sbin
	cvsroot  i386-redhat-linux  lib       share
	dict     i486-linux-libc5   libexec   src
	doc      include            local     tmp

	$ ls /usr/ | xargs -n 5 echo
	X11R6 bin cvsroot dict doc
	etc games i386-redhat-linux i486-linux-libc5 include
	info kerberos lib libexec local
	man sbin share src tmp
	$

Здесь результат выполнения ls /usr/ направляется на вход xargs -n 5, который разбивает полученные строки по пять штук и передает их в качестве аргумента команде echo, как нетрудно догадаться число параметров задается с помощью параметра -n.

В нашем случае указывать количество параметров не требуется, так как оно в данном случае несущественно, главное чтобы ограничение на размер аргумента не было превышено, а эту задачу xargs решает без посторонней помощи:

	$ locate / | xargs ls -ld | wc -l
	  70968
	$

Как видим такой вариант в отличие от предыдущего сработал.

Когда locate не катит.

Как всегда, отрицательные стороны locate вытекают прямиком из его положительных сторон. Так информация о файлах в базе может устареть с момента последнего обновления, и не соответствовать текущему состоянию файловой системы, некоторые файлы могут быть удалены, некоторые переименованы, другие добавлены. И если с удалением проблем вобщем не возникает, потому что locate после поиска в своей базе проверяет наличие найденных файлов в системе, то с новыми или переименованными файлами locate не дружит, они результатах будут отсутствовать:

	$ locate somefile.txt        <-- ищем файл somefile.txt которого нет
	$ touch /tmp/somefile.txt    <-- создаем его
	$ locate /tmp/simefile.txt   <-- пытаемся его найти, он не находится
	$ su                         <-- тогда логинимся под root,
	Password:
	# updatedb                    -- и обновляем базу locate
	# exit                        -- после чего возвращаемся
	exit
	$ locate somefile.txt        <-- теперь поиск успешен
	/tmp/somefile.txt
	$ mv /tmp/somefile.{txt,old} <-- переименовываем
	$ locate /tmp/somefile.txt   <-- под старым именем не находим
	$ locate /tmp/somefile.old   <-- под новым тоже не находим
	$ su                         <-- еще раз обновляем базу под root-ом
	Password:
	# updatedb
	# exit
	$ locate /tmp/somefile.old   <-- теперь все OK под новым именем находится
	/tmp/somefile.old
	$ locate /tmp/somefile.txt    -- под старым нет
	$

В случае если вы и пользователь или root в одном лице, то проблема решается обновлением базы руками, иначе придется пользоваться чемто более мощным, типа find.

Еще один момент, на который стоит обратить внимание, это то что locate хранит имя самого файла и путь к нему как строку, в связи с чем в общем случае узнать является ли найденная строка файлом, символической ссылкой, или каталогом непосредственно с помощью locate нельзя.

Иногда использование locate не эффективно, так был приведен немного исскуственный пример, когда мы находили все файлы в системе, а потом выводили их атрибуты с помощью ls -ld. В данном случае более правильное решение есть использовать тотже find, дело в том что в вышеприведенном случае сканирование системы происходит все равно, только делает это не locate, а ls, добавте сюда накладные расходы на трубопровод, xargs, в результате получаем:

$ cat /tmp/l
locate -f proc / |  xargs -n 1000 ls -ld

$ cat /tmp/f
find / -ls 2>/dev/null

$ time /tmp/f >/dev/null
3.83user 2.80system 0:06.99elapsed 94%CPU (0avgtext+0avgdata 0maxresident)k
0inputs+0outputs (358major+147minor)pagefaults 0swaps

$ time /tmp/l >/dev/null
5.41user 5.92system 0:11.62elapsed 97%CPU (0avgtext+0avgdata 0maxresident)k
0inputs+0outputs (28176major+11719minor)pagefaults 0swaps

Как видно в данном случае locate с компанией сел в лужу, выполняя поставленную задачу в два раза медленнее чем find. Конечно пример надуманный, но иллюстрирует тот факт что перед решением любой задачи не мешает пораскинуть мозгами!

На этом разрешите откланяться. До новых встреч.

Приборы и материалы

Смотри также: Если вы еще не являетесь счастливым обладателем locate, том его можно взять с сайта GNU в составе Findutils 4.1.