Как было сказано ранее
решает практически все задачи которые могут возникнуть у пользователя
в связи с поиском и последующей обработкой нужных файлов или каталогов.
Однако, довольно часто, возникают ситуации когда вам с одной стороны не нужна
вся мощь
, а с другой хотелось чтобы
поиск происходил побыстрее, и без значительной загрузки системы.
Ведь запустив find с каким нибудь хитрым условием, да еще вызывающий
внешние команды, да указав начать поиск с корневой директории, можно
добиться того что система будет настолько загружена, что ваш
системный администратор грешным делом подумает о визите кул хацкеров,
но мы конечно не звери и нашего администратора пугать не будем.
Поэтому для глобального поиска воспользуемся утилитой locate.
Данная утилита просто незаменима в случае если вам хотя бы
приблизительно известно имя файла, который нужно найти.
Отличительная особенность данной команды, скажем от того же
find, в том что при работе она не сканирует по настоящему
файловую систему, поиск идет в предварительно построенной базе,
в которой хранится как-бы слепок с файловой системы.
Такой слепок выполняется
с помощью команды
или updatedb, которая
по настоящему перелопачивает ваши жесткие или сетевые диски, а
имена всех найденных файлов записывает в базу. Естественно что
данная процедура довольно ресурсоемкая, и может занимать довольно
длительное время. Ее запуск обычно поручают crontab,
который запускает
с требуемой частотой. Частота обновления
базы зависит от того насколько часто обновляется содержимое файловой системы,
а также насколько важна актуальность данных. Так обычно обновление
базы выполняется автоматически раз в неделю, или вручную, после того как вы или
системный администратор установили новую партию свежего ПО. Отмечу,
для того чтобы обновить базу, нужно иметь права суперпользователя.
Приведу простейший пример использования:
$ 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 $
Из приведенных примеров видно три существенных момента, касающихся
поведения
. Во-первых ищутся все файлы и каталоги в именах
которых встречается подстрока заданная в качестве аргумента. Во-вторых
файлы выводятся включая полный путь к ним. В-третьих
заданная подстрока вообще может не входить в имя самого файла,
а встречаться в его пути. Так во втором примере в список найденных
файлов было полностью включено содержимое каталога mpg123-0.59r.
Иногда требуется более точный поиск, когда нужно ограничить то место куда может входить заданная подстрока. Скажем если нам нужно найти только файлы и каталоги в название которых входит mpg123. В данном случае можно использовать шаблоны аля bash (помните *, ?, [...]) или более продвинутый вариант использующий регулярные выражения. Я предпочитаю последний, как более мощный и продвинутый.
Для того чтобы сообщить locate что вы хотите использовать
регулярные выражения, нужно указать форму
.
Так в нашем случае запрос будет выглядеть следующим образом:
$ locate -r "mpg123[^/]*$" /usr/doc/mpg123-0.59r /usr/man/man1/mpg123.1.gz /usr/bin/mpg123 $
Строка mpg123[^/]*$ - просит
найти
те файлы в которых после подстроки mpg123 могут быть
ноль или более символов, кроме символа /, после чего
идет конец строки. Таким образом из результата поиска исключаются
строки
Еще одна полезная возможность - это форма вызова
.
Параметр
говорит о том что нужно произвести нечувствительный
к регистру поиск:
$ 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 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 $
В данном примере
первой командой мы получили список интересующих нас файлов, а второй передали
этот список команде
, в результате чего получили чудный
список с требуемой информацией. Кто забыл чего делает
читать тут
Работаем с историей команд. Параметр
сообщает
что вместо содержимого каталогов, выводить
их атрибуты.
Способ с подстановкой подходит в том случае если у нас не много файлов.
В противном случае мы можем столкнутся с ограничением на длину
строки параметров передаваемых
. К примеру:
$ locate / | wc -l # <--- locate - выводит все файлы в системе # wc - подсчитывает их количество 70968 $ ls -ld `locate /` | wc -l bash: /bin/ls: Argument list too long 0 $
Как видим вариант не прошел. Поэтому если
ожидается большое количество файлов на выходе, более предпочтительнее
будет воспользоваться утилитой 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 $
Здесь результат выполнения
направляется
на вход
, который разбивает полученные строки
по пять штук и передает их в качестве аргумента команде
,
как нетрудно догадаться число параметров задается с помощью
параметра
.
В нашем случае указывать количество параметров не требуется,
так как оно в данном случае несущественно, главное чтобы ограничение
на размер аргумента не было превышено, а эту задачу
решает без посторонней помощи:
$ locate / | xargs ls -ld | wc -l 70968 $
Как видим такой вариант в отличие от предыдущего сработал.
Как всегда, отрицательные стороны
вытекают
прямиком из его положительных сторон. Так информация о файлах
в базе может устареть с момента последнего обновления, и не
соответствовать текущему состоянию файловой системы, некоторые файлы
могут быть удалены, некоторые переименованы, другие добавлены.
И если с удалением проблем вобщем не возникает, потому что
после поиска в своей базе проверяет наличие
найденных файлов в системе, то с новыми или переименованными
файлами
не дружит, они результатах
будут отсутствовать:
$ 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.
Еще один момент, на который стоит обратить внимание, это то
что
хранит имя самого файла и путь к нему как строку,
в связи с чем в общем случае узнать является ли найденная строка
файлом, символической ссылкой, или каталогом непосредственно с помощью
нельзя.
Иногда использование
не эффективно, так
был приведен немного исскуственный пример, когда мы находили все
файлы в системе, а потом выводили их атрибуты с помощью
.
В данном случае более правильное решение есть использовать тотже
find, дело в том что в вышеприведенном случае сканирование системы
происходит все равно, только делает это не
, а
, добавте сюда накладные расходы на трубопровод,
, в результате получаем:
$ 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
Как видно в данном случае
с компанией сел в лужу,
выполняя поставленную задачу в два раза медленнее чем
.
Конечно пример надуманный, но иллюстрирует тот факт что перед решением
любой задачи не мешает пораскинуть мозгами!
На этом разрешите откланяться. До новых встреч.