find - це одна з найстаріших утиліт UNIX®. Вона призначена для рекурсивного сканування одного чи кількох каталогів і пошуку в них файлів, що відповідають певному набору критеріїв. Проти всю свою корисність її синтаксис не занадто зрозумілий, і для її використання потрібно певна практика. Загальний синтаксис:
find [опції] [каталоги] [критерій1] ... [критерійN] [дія]
Якщо ви не вкажете жодного каталогу, find виконуватиме пошук у поточному каталозі. Якщо ви не вкажете критерії, це буде еквівалентно “істині”, тобто будуть знайдені всі файли. Опції, критерії і дії настільки численні, що тут ми згадаємо тільки деякі з них. Ось деякі з опцій:
-xdev
: не шукати в каталогах, що знаходяться в інших файлових системах.
-mindepth <n>
: спускатися до файлів як мінімум на n
рівнів нижче зазначеного каталогу.
-maxdepth <n>
: шукати файли не нижче n
рівнів щодо зазначеного каталогу.
-follow
: переходити по символічним посиланням, якщо вони посилаються на каталоги. За умовчанням find не переходить по символічним посиланням.
-daystart
: при використанні перевірок, пов'язаних з часом (див. нижче), замість значення за умовчанням (24 години назад від поточного часу) за точку відліку приймається початок поточного дня.
Критеріями може бути одна чи кілька атомарних перевірок. Ось деякі корисні перевірки:
-type <тип_файла>
: пошук файла зазначеного типу. Типом_файлу
може бути: f
(звичайний файл), d
(каталог), l
(символічне посилання), s
(сокет), b
(файл блокового типу), c
(файл символьного типу) чи p
(іменований канал).
-name <шаблон>
: пошук файлів, чиї імена відповідають зазначеному шаблону. У опції під шаблоном припускається підстановка імен файлів (див. Параграф 3, “Шаблони підстановки в командному процесорі”).
-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>
. Ви повинні заекранувати (дезактивувати) круглі дужки, інакше їх буде інтерпретовано 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
. Для цього потрібно зробити наступне[27]:
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'і... Інше рішення - взяти круглі дужки в подвійні чи одинарні лапки, але тут бажанішим є використання зворотної скісної риски, бо нам потрібно ізолювати один символ.
І, нарешті, ось команда, яка виконуватиметься для кожного файла:
-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, як показано в наступному розділі.