Критерии отбора файлов могут группироваться практически любым образом. Так, в форме
$ find ~/ -name *.tar.gz newer filename
она выберет в домашнем каталоге пользователя все компрессированные архивы, созданные после файла с именем filename. По умолчанию между критериями отбора предполагается наличие логического оператора AND (логическое «И»). То есть будут отыскиваться файлы, удовлетворяющие и маске имени, и соответствующему атрибуту времени. Если требуется использование оператора OR (логическое «ИЛИ»), он должен быть явно определен в виде дополнительной опции -o между опциями поиска. Так, команда:
$ find ~/ -mtime -2 -o newer filename
призвана отобрать файлы, созданные менее двух суток назад, или же — позднее, чем файл filename.
Особенность GNU-реализации команды find (как, впрочем, и ее тезки из числа BSD-утилит) — то, что она по умолчанию выводит список отобранных в соответствии с заданными критериями файлов на экран, не требуя дополнительных опций действия. Однако, как говорят, в других Unix-системах (помнится, даже и в некоторых реализациях Linux мне такое встречалось) указание какой-либо из таких опций — обязательно. Так что рассмотрим их по порядку.
Для выведения списка отобранных файлов на экран в общем случае предназначена опция -print. Вывод этот имеет примерно следующий вид:
$ find . -name f* -print
./file1
./file2
./dir1/file3
Сходный смысл имеет и опция -ls, однако она выводит более полные сведения о найденных файлах, аналогично команде ls с опциями -dgils:
$ find / -fstype ext3 -name zsh -ls
88161 511 -rwxr-xr-x 1 root root 519320 Ноя 23 15:50 /bin/zsh
Важное, как мне кажется, замечание. Если команда указанного вида будет дана от лица обычного пользователя (не root-оператора), кроме приведенной выше строки вывода, последуют многочисленные сообщения вроде
find: /root: Permission denied
указывающие на каталоги, закрытые для просмотра обычным пользователем, и весьма мешающие восприятию результатов поиска. Чтобы подавить их, следует перенаправить вывод сообщения об ошибках в файл /dev/null, то есть указать им «Дорогу никуда»:
$ find / -fstype ext3 -name zsh -ls 2> /dev/null
Идем далее. Опция -delete уничтожит все файлы, отобранные по указанным критериям. Так, командой
$ find ~ -atime +100 -delete
будут автоматически стерты все файлы, к которым не было обращения за последние 100 дней (из молчаливого предположения, что раз к ним три месяца не обращались — значит, они и вообще не нужны). Истреблению подвергнутся файлы в подкаталогах любого уровня вложенности — но не включающие их подкаталоги (если, конечно, последние сами не подпадают под критерии отбора).
И, наконец, опция -exec — именно ею обусловлено величие утилиты find. В качестве значения ее можно указать любую команду с необходимыми опциями — и она будет выполнена над отобранными файлами, которые будут рассматриваться в качестве ее аргументов. Проиллюстрируем это на примере.
Использовать для удаления файлов опцию -delete, как мы это только что сделали — не самое здоровое решение, ибо файлы при этом удаляются без запроса, и можно случайно удалить что-нибудь нужное. И потому достигнем той же цели следующим образом:
$ find ~/ -atime +100 -exec rm -i {} ;
В этом случае (вне зависимости от настроек псевдонимов командной оболочки) на удаление каждого отобранного файла будет запрашиваться подтверждение.
Обращаю внимание на последовательность символов {} \; (с пробелом между закрывающей фигурной скобкой и обратным слэшем) в конце строки. Пара фигурных скобок {} символизирует, что свои аргументы исполняемая команда (в примере — rm) получает от результатов отбора команды find, точка с запятой означает завершение команды-значения опции -exec, а обратный слэш экранирует ее специальное значение от интерпретации командной оболочкой.
Кроме опции действия -exec, у команды find есть ещё одна, близкая по смыслу, опция — -ok. Она также вызывает некую произвольную команду, которой в качестве аргументов передаются имена файлов, отобранные по критериям, заданным опцией (опциями) поиска. Однако перед выполнением каждой операции над каждым файлом запрашивается подтверждение.
Приведенный на предыдущей странице пример, хотя и вполне жизненный, достаточно элементарен. Рассмотрим более сложный случай — собирание в один каталог всех скриншотов в формате PNG, разбросанных по древу домашнего каталога:
$ find ~/ -name *.png -exec cp {} imagesdir ;
В результате все png-файлы будут изысканы и скопированы (или — перемещёны, если воспользоваться командой mv вместо cp) в одно место.
А теперь — вариант решения задачи, которая казалась мне некогда трудно разрешимой: рекурсивное присвоение необходимых атрибутов доступа в разветвленном дереве каталогов — различных для регулярных файлов и каталогов.