2. find: Пошук файлів за певними критеріями

find - це одна з найстаріших утиліт UNIX®. Вона призначена для рекурсивного сканування одного чи кількох каталогів і пошуку в них файлів, що відповідають певному набору критеріїв. Проти всю свою корисність її синтаксис не занадто зрозумілий, і для її використання потрібно певна практика. Загальний синтаксис:

find [опції] [каталоги] [критерій1] ... [критерійN] [дія]

Якщо ви не вкажете жодного каталогу, find виконуватиме пошук у поточному каталозі. Якщо ви не вкажете критерії, це буде еквівалентно “істині”, тобто будуть знайдені всі файли. Опції, критерії і дії настільки численні, що тут ми згадаємо тільки деякі з них. Ось деякі з опцій:

Критеріями може бути одна чи кілька атомарних перевірок. Ось деякі корисні перевірки:

Існує багато інших перевірок. Для одержання додаткового інформації зверніться до сторінці керівництва find(1). Перевірки можна комбінувати так:

І, на закінчення, ви можете вказати дію для кожного знайденого файла. Найчастіше використовуються:

Найкращим засобом розібратися з усіма опціями і параметрами буде розгляд кількох прикладів. Нам потрібно знайти всі каталоги в /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, як показано в наступному розділі.



[27] [27]

[2727] Зверніть увагу, в цьому прикладі потрібно, щоб каталоги /var/www і /var/www/obsolete перебували в одній файловій системі!