Библиотека сайта rus-linux.net
find: Поиск файлов по определенным критериям |
||
---|---|---|
Chapter 5. Утилиты командной строки |
find: Поиск файлов по определенным критериям
find - это одна из старейших утилит UNIX®. Она предназначена для рекурсивного сканирования одного или нескольких каталогов и поиска в них файлов, соответствующих определённому набору критериев. При всей своей полезности её синтаксис не слишком понятен, и для её использования требуется некоторая практика. Общий синтаксис:
find [опции] [каталоги] [критерий] [действие] |
Если вы не укажете ни одного каталога, find будет выполнять поиск в текущем каталоге. Если вы не укажете критерии, это будет эквивалентно “истине”, т.е. будут найдены все файлы. Опции, критерии и действия настолько многочисленны, что мы здесь упомянем только некоторые из них. Давайте начнем с опций:
-xdev
: не искать в каталогах, находящихся в других файловых системах.-mindepth <n>
: спускаться при поиске файлов как минимум наn
уровней ниже указанного каталога.-maxdepth <n>
: искать файлы не нижеn
уровней относительно указанного каталога.-follow
: следовать по символическим ссылкам, если они ссылаются на каталоги. По умолчанию find не переходит по символическим ссылкам.-daystart
: при использовании проверок, связанных со временем (см. ниже), вместо значения по умолчанию (24 часа назад от текущего времени) за точку отсчета принимается начало текущего дня.
Критериями могут быть одна или несколько атомарных проверок. Вот некоторые полезные проверки:
-type <тип_файла>
: поиск файла указанного типа.<тип_файла>
может быть:f
(обычный файл),d
(каталог),l
(символическая ссылка),s
(сокет),b
(файл блочного типа),c
(файл символьного типа) илиp
(именованный канал).-
-name <шаблон>
: поиск файлов, чьи имена соответствуют указанному шаблону. В этой опции под шаблоном подразумевается универсализация имен файлов (см. главу «Шаблоны универсализации в командном процессоре»). -iname <шаблон>
: аналог-name
, но без учета регистра.-atime <n>
,-amin <n>
: поиск файлов, обращение к которым был выполненоn
дней назад (-atime
) илиn
минут назад (-amin
). Вы также можете указать опцию+<n>
или-<n>
, в этом случае будут выполнен поиск файлов, обращение к которым было выполнено больше или меньше, чемn
дней/минут назад.-anewer <файл>
: поиск файлов, обращение к которым было выполнено позже, чем кфайлу
.-ctime <n>
,-cmin <n>
,-cnewer <файл>
: аналог-atime
,-amin
и-anewer
, но применимо к дате последнего изменения содержимого файла.-
-regex <шаблон>
: аналог-name
, но подшаблоном
подразумевается регулярное выражение. -iregex <шаблон>
: аналог-regex
, но без учета регистра.
Существует много других проверок, для получения дополнительной информации обратитесь к странице руководства find(1). Проверки можно комбинировать одним из следующих способов:
<c1> -a <c2>
: истина, если истинны оба выраженияc1
иc2
; опция-a
является неявной, поэтому, если вам нужно проверить все выраженияc1
,c2
иc3
, вы можете ввести<c1> <c2> <c3>
.<c1> -o <c2>
: истина, если истинно любое из выраженийc1
илиc2
. Обратите внимание, что опция-o
имеет более низкий приоритет, чем-a
, поэтому, если вам нужно найти файлы, удовлетворяющие критериюc1
илиc2
и удовлетворяющие критериюc3
, вам понадобится использовать скобки и ввести( <c1> -o <c2> ) -a <c3>
. Вы должны дезактивировать (escape) круглые скобки, иначе они будут интерпретированыshell
'ом!-not <c1>
: инвертирует проверкуc1
, поэтому-not <c1>
будет истиной, если<c1>
- ложь.
И в заключение, вы можете указать действие для каждого найденного файла. Вот наиболее часто используемые:
-print
: просто выводит имена файлов на стандартный вывод. Это действие по умолчанию.-ls
: для каждого найденного файла выводит на стандартный вывод эквивалент команды ls -ilds.-exec <команда>
: для каждого найденного файла выполняет<команду>
. Командная строка<команда>
должна заканчиваеться символом;
, который вы должны дезактивировать, чтобыshell
его не интерпретировал; положение в файле отмечается при помощи{}
. Смотрите примеры по использованию.-ok <команда>
: аналог-exec
, но спрашивает подтверждение перед каждой командой.
Наилучшим способом
разобраться со всеми опциями и параметрами будет рассмотрение
примеров. Допустим, что вам нужно найти все каталоги в /usr/share
.
Для этого введите:
find /usr/share -type d |
Предположим, что у
вас есть HTTP-сервер, все ваши HTML-файлы находятся в каталоге
/var/www/html
,
в котором вы в данный момент находитесь. Вам нужно найти все файлы,
содержимое которых не изменялось в течение месяца. Поскольку эти
страницы писали разные авторы, некоторые файлы имеют расширение html
,
а некоторые - htm
.
Вам нужно поместить ссылки на эти файлы в каталог /var/www/obsolete
.
Для этого нужно сделать следующее[17]:
find \( -name "*.htm" -o -name "*.html" \) -a -ctime -30 \ -exec ln {} /var/www/obsolete \; |
Этот пример несколько сложноват и требует небольшого пояснения. Критерий поиска следующий:
\( -name "*.htm" -o -name "*.html" \) -a -ctime -30 |
он делает то, что
нам нужно - находит все файлы, имена которых заканчиваются на .htm
или .html
“
\( -name "*.htm" -o -name
"*.html" \)
”, и
(-a
) те файлы,
которые не были изменены на протяжении последних 30 дней или, грубо
говоря, месяца (-ctime -30
).
Обратите внимание на скобки: здесь они необходимы потому, что опция
-a
имеет более
высокий приоритет. Если бы они отсутствовали, были бы найдены все
файлы, заканчивающиеся на .htm
,
плюс все файлы, заканчивающиеся на .html
,
которые не были изменены в течение месяца, а это не то, что нам
нужно. Также обратите внимание, что круглые скобки дезактивированы
для shell
'а:
если бы мы ввели ( .. )
вместо \( .. \)
,
командный процессор интерпретировал бы их и попытался выполнить -name
"*.htm" -o -name "*.html"
в sub-shell'e... Другое решение - заключить круглые скобки в двойные
или одинарные кавычки, здесь предпочтительней использовать обратную
косую черту,т.к. нам нужно изолировать только один символ.
И, наконец, вот команда, которая будет выполнена для каждого файла:
-exec ln {} /var/www/obsolete \; |
Здесь вы также
должны дезактивировать знак ;
,
в противном случае командный процессор интерпретирует его как
разделитель команд. Если вы забудете сделать это, find
пожалуется, что для -exec
отсутствует аргумент.
Последний пример:
у вас есть огромный каталог (/shared/images
),
содержащий все виды изображений. Вы регулярно используете команду
touch для обновления в этом каталоге временной метки у файла с именем
stamp
с тем,
чтобы иметь привязку ко времени. Вам нужно найти все изображения JPEG
более новые, чем файл stamp
,
но поскольку вы получали изображения из различных источников, эти
файлы имеют расширения jpg
,
jpeg
, JPG
или JPEG
. Вы
также хотите избежать поиска в каталоге old
.
И вам нужно, чтобы этот список файлов был отправлен к вам по почте, а
ваше имя пользователя - peter
:
find /shared/images -cnewer \ /shared/images/stamp \ -a -iregex ".*\.jpe?g" \ -a -not -regex ".*/old/.*" \ | mail peter -s "Новые изображения" |
Конечно, эта команда не слишком полезна, если вы каждый раз должны набирать её, и вы бы предпочли, чтобы она выполнялось регулярно. Простым способом периодического запуска команды является использование демона cron, как показано в следующем разделе.
[17]
Обратите внимание, что в этом примере
требуется, чтобы каталоги /var/www
и /var/www/obsolete
находились в одной файловой системе!
Операции с файлами и фильтрация |
Запуск команд по расписанию |