User Tools

Site Tools


find

find

Поиск файлов и директорий

В отличие от программы locate, выполняющей поиск файлов по именам, программа find ищет файлы согласно заданным атрибутам в указанном каталоге (и во вложенных директориях).

В простейшем случае программе find можно передать одно или несколько имен каталогов для поиска. Например, с ее помощью можно получить список содержимого домашней директории:

find ~

Список может быть весьма длинный. Так как список выводится в стандартный вывод, его можно передать по конвейеру другим программам. Воспользуемся программой wc, чтобы подсчитать число файлов:

find ~ | wc -l
15332

Вся прелесть команды find в том, что ее можно использовать для поиска файлов, соответствующих определенным критериям. Она делает это посредством применения проверок, операций и параметров.

Проверки

Допустим, нужно получить список директорий. Для этого добавим в команду следующую проверку:

find ~ -type d | wc -l
4590

Добавив проверку -type d, поиск ограничился только каталогами. Но точно так же можно ограничить поиск только обычными файлами:

find ~ -type f | wc -l
10726

Проверки типов файлов, наиболее часто используемые с командой find.

Тип файлов Описание
b Специальный файл блочного устройства
c Специальный файл символьного устройства
d Директория
f Обычный файл
l Символическая ссылка

Добавив дополнительные проверки, можно выполнять поиск файлов по размеру и имени. Попробуем найти все обычные файлы с именами, соответствующими шаблону *.jpg, и имеющие размер больше 1 мегабайта:

find ~ -type f -name "*.JPG" -size +1M | wc -l
14

В примере выше, была добавлена проверка -name с шаблоном имени файла. Обратите внимание, что шаблон заключен в кавычки, чтобы предотвратить подстановку имен файлов командной оболочкой. Далее была добавлена проверка -size со строкой +1M. Начальный символ «плюс» указывает, что требуется искать файлы, размер которых превышает указанное число. Начальный символ «минус» изменил бы значение строки на противоположное: «меньше указанного числа». Число без знака означает: «в точности соответствует значению». Буква M в конце определяет единицы измерения — мегабайты (Megabytes).

Символы, которые можно использовать для обозначения единиц измерения.

Символ Единица измерения
b Блоки размером по 512 байт (используется по умолчанию, если иное не указано явно)
c Байты
w 2-байтные слова
k Килобайты (Kilobytes, блоки по 1024 байт)
M Мегабайты (Megabytes, блоки по 1 048 576 байт)
G Гигабайты (Gigabytes, блоки по 1 073 741 824 байт)

Команда find поддерживает множество разнообразных проверок. В таблице ниже приводится краткое описание наиболее часто используемых из них. Обратите внимание, что в случаях, когда требуется числовой аргумент, допустимо использование формы записи с символами + и -, описанный выше.

Проверка Описание
-cmin n Соответствует файлам или каталогам, содержимое или атрибуты которых последний раз изменялись точно n минут назад. Чтобы выразить условие «менее n минут назад», используйте -n; чтобы выразить условие «более n минут назад», используйте +n
-cnewer имя Соответствует файлам или каталогам, содержимое или атрибуты которых последний раз изменялись позже, чем у файла с указанным именем
-ctime n Соответствует файлам или каталогам, содержимое или атрибуты (то есть разрешения) которых последний раз изменялись более чем n*24 часов назад
-empty Соответствует пустым файлам и каталогам
-group группа Соответствует файлам или каталогам, принадлежащим указанной группе. Группа может задаваться именем или числовым идентификатором групп
-iname шаблон Действует так же, как проверка -name, но различает регистр символов
-inum n Соответствует файлам с номером индексного узла (inode) n. Эту проверку удобно использовать для поиска всех жестких ссылок на определенный индексный узел
-mmin n Соответствует файлам или каталогам, содержимое которых последний раз изменялось n минут назад
-mtime n Соответствует файлам или каталогам, содержимое которых последний раз изменялось n*24 часов назад
-name шаблон Соответствует файлам и каталогам, имена которых совпадают с указанным шаблоном
-newer имя Соответствует файлам и каталогам, содержимое которых последний раз изменялось позже, чем у файла с указанным именем. Эта проверка может пригодиться в сценариях, выполняющих резервное копирование файлов. Каждый раз, в процессе создания резервной копии, можно обновлять файл (например, файл журнала) и затем с помощью find определять, какие файлы изменились с момента последнего обновления
-nouser Соответствует файлам и каталогам, не принадлежащим какому-либо допустимому пользователю. Эту проверку можно использовать для поиска файлов, принадлежащих удаленным учетным записям, или для обнаружения следов злоумышленников
-nogroup Соответствует файлам и каталогам, не принадлежащим какой-либо допустимой группе
-perm режим Соответствует файлам или каталогам с указанным режимом доступа. Режим может задаваться восьмеричным числом или иметь символическую форму
-samefile имя Действует так же, как проверка -inum. Соответствует файлам с тем же номером индексного узла (inode), что и файл с указанным именем
-size n Соответствует файлам с размером n
-type c Соответствует файлам с типом c
-user имя Соответствует файлам или каталогам, принадлежащим пользователю с указанным именем. Аргумент имя может быть именем или числовым идентификатором пользователя

Это не полный список, все остальное в man find

Операторы

Несмотря на большое число проверок, поддерживаемых командой find, все еще нужны способы определения логических отношений между проверками. Например, представьте, что в некотором каталоге мы хотим найти все файлы и подкаталоги с небезопасными разрешениями. Для этого можно было бы выполнить поиск всех файлов с разрешениями, отличающимися от 0600, и каталогов с разрешениями, отличающимися от 0700. К счастью, find поддерживает возможность комбинирования проверок с помощью логических операторов с целью определить более сложные критерии отбора. Выразить вышеупомянутую проверку можно так:

find ~ \( -type f -not -perm 0755 \) -or \( -type d -not -perm 0700 \) | wc -l
15054

Логические операторы, поддерживаемые командой find find_logic

Команда Описание команды
-and Соответствует, если выполняются условия в проверках с обеих сторон от оператора. Можно сократить до -a. Обратите внимание, что в отсутствие операторов по умолчанию подразумевается -and
-or Соответствует, если выполняется условие с одной из сторон от оператора. Можно сократить до -o
-not Соответствует, если условие в проверке, следующей за оператором, не выполняется. Можно сократить до -!
( ) Группируют проверки и операторы для формирования крупных выражений. Используются для управления порядком проверок. По умолчанию проверки выполняются слева направо. Часто используются для изменения порядка проверок по умолчанию, чтобы получить желаемый результат. Даже если скобки не нужны, иногда полезно включать их, чтобы сделать команды более наглядными. Не забывайте, что круглые скобки имеют специальное значение для командной оболочки, поэтому их нужно экранировать, чтобы они были переданы команде find как аргументы. Обычно экранирование выполняют с помощью символа «обратный слеш»

Предопределенные операции

find позволяет выполнять операции, основываясь на результатах поиска.

Предопределенные операции, поддерживаемые командой find

Команда Описание команды
-delete Удаляет текущий найденный файл
-ls Действует эквивалентно команде ls -dils в отношении найденного файла. Результат выводится в стандартный вывод
-print Выводит полный путь к найденному файлу в стандартный вывод. Эта операция выполняется по умолчанию, если не указана никакая другая
-quit Завершает выполнение команды после обнаружения первого совпадения

Программу find можно использовать для удаления файлов, соответствующих определенным критериям. Например, следующая команда удалит все файлы с расширением .bak

find ~ -type f -name "*.bak" -delete

<WRAP center round important 90%> Nota Bene! Операцию -delete следует использовать с особыми предосторожностями. Всегда предварительно проверяйте команду, подставив операцию -print вместо -delete, чтобы убедиться, что она не удалит ничего лишнего. </WRAP>

find ~ -type f -name "*.bak" -print

Как видите, эта команда ищет обычные файлы (-type f) с расширением .bak (-name '*.bak') и выводит относительные пути к ним в стандартный вывод (-print). Однако такой порядок работы команды определяется логическими отношениями между всеми проверками и операциями. Как вы помните, между проверками и операциями по умолчанию подразумевается отношение -and. Ту же команду можно выразить, добавив логические операторы:

find ~ -type f -and -name '*.bak' -and -print

Операции, определяемые пользователем

Помимо предопределенных операций можно также вызывать произвольные команды. Традиционно с этой целью используется операция -exec. Её синтаксис показан ниже:

-exec команда {} ;

Где:

  • команда – это имя команды;
  • {} – символическое представление текущего пути к файлу;
  • точка с запятой – обязательный разделитель, обозначающий конец команды.

Следующий пример демонстрирует использование -exec для получения эффекта, аналогичного операции -delete, обсуждавшейся выше:

find ~ -type f -and -name '*.bak' -and -exec rm '{}' ';'

И снова, поскольку фигурные скобки и точка с запятой имеют специальное значение для командной оболочки, они должны заключаться в кавычки или экранироваться.

Кроме того, существует возможность выполнять пользовательские операции интерактивно. Если заменить операцию –exec операцией -ok, перед выполнением каждой указанной команды будет выводиться запрос:

find ~ -type f -name '*.bak' -ok ls -lh '{}' ';'
< ls ... /root/Two Worlds.txt.bak > ? y
-rw-r--r-- 1 root root 0 Jun  8 16:56 '/root/Two Worlds.txt.bak'
< ls ... /root/Out.txt.bak > ? y
-rw-r--r-- 1 root root 45 Jun  8 16:56 /root/Out.txt.bak

Эта команда ищет файлы с расширениями .bak и для каждого найденного файла выполняет команду ls -l. Операция -ok запрашивает подтверждение у пользователя, прежде чем выполнить команду ls.

Увеличение эффективности

Каждый раз, когда обнаруживается файл, соответствующий критериям, операция -exec запускает новый экземпляр указанной команды. Но иногда желательно объединить все результаты поиска и запустить единственный экземпляр команды. Например, вместо последовательности команд, такой как:

ls -l file1
ls -l file2

Предпочтительнее было бы выполнить команду:

ls -l file1 file2

Здесь команда выполняется только один раз, а не несколько. Существует два способа добиться этого: традиционный, с использованием внешней команды xargs, и альтернативный, с использованием новой возможности в самой команде find. Обсудим сначала альтернативный способ.

Если заменить завершающий символ «точка с запятой» знаком «плюс», в команде find активируется функция объединения результатов в список аргументов для вызова единственного экземпляра требуемой команды. Вернемся к нашему примеру.

Команда:

find ~ -type f -name 'file*' -exec ls -l '{}' ';'
-rw-r--r-- 1 nevvad nevvad 9 Jun  8 22:50 /home/nevvad/file2
-rw-r--r-- 1 nevvad nevvad 9 Jun  8 22:50 /home/nevvad/file1

будет вызывать ls для каждого найденного файла. Изменив команду, как показано ниже:

find ~ -type f -name 'file*' -exec ls -l '{}' +
-rw-r--r-- 1 nevvad nevvad 9 Jun  8 22:50 /home/nevvad/file1
-rw-r--r-- 1 nevvad nevvad 9 Jun  8 22:50 /home/nevvad/file2

получим тот же результат, но система выполнит команду ls только один раз.

xargs

Команда xargs предлагает очень интересную возможность. Она принимает входные данные со стандартного ввода и преобразует их в список аргументов для указанной команды. В данном примере ее можно было бы использовать так:

find ~ -type f -name 'file*' -print | xargs ls -l
-rw-r--r-- 1 nevvad nevvad 9 Jun  8 22:50 /home/nevvad/file1
-rw-r--r-- 1 nevvad nevvad 9 Jun  8 22:50 /home/nevvad/file2

Здесь вывод команды find передается по конвейеру команде xargs, которая, в свою очередь, конструирует список аргументов для команды ls и выполняет ее.

<WRAP center round tip 90%> Nota Bene! Несмотря на то, что в командную строку можно включить большое число аргументов, оно не бесконечно. Не исключено, что в результате получится команда, слишком длинная для командной оболочки. Когда длина командной строки превышает максимально допустимый размер, xargs выполнит указанную команду с максимально возможным числом аргументов и затем повторит процесс, пока не исчерпает все, что получит со стандартного ввода. Чтобы увидеть максимально возможную длину командной строки, выполните xargs с параметром –show-limits </WRAP>

Обработка файлов с необычными именами

<WRAP center round box 90%> Unix-подобные системы позволяют встраивать в имена файлов пробелы (и даже символы перевода строки). Это порождает проблемы при выполнении программ, таких как xargs, конструирующих списки аргументов для других программ. Внутренние пробелы интерпретируются как разделители, и получившаяся команда будет интерпретировать слова, разделенные пробелами, как отдельные аргументы. Для решения этой проблемы find и xarg предлагают использовать в качестве разделителя аргументов пустой символ (null character). В кодировке ASCII пустой символ определен как символ с нулевым кодом (в противоположность пробелу, например, который в кодировке ASCII определен как символ с кодом 32). Команда find поддерживает операцию -print0, которая производит вывод имен файлов, разделенных пустым символом, а команда xargs имеет параметр –null, позволяющий организовать прием значений, разделенных пустым символом. </WRAP> Пример:

find ~ -type f -name 'file*' -print0 | xargs --null ls -l

Этот прием гарантирует правильную обработку любых имен файлов, даже содержащих пробелы.

Практическое применение

Сначала создадим песочницу с множеством файлов и каталогов:

mkdir -p playground/dir-{001..100}
touch playground/dir-{001..100}/file-{A..Z}

В песочнице были создали 100 файлов с именем file-A. Давайте найдем их:

find playground/ -type f -name "file-A" | wc -l
100

<WRAP center round tip 90%> Nota Bene! В отличие от ls, find возвращает результаты в несортированном порядке. Порядок определяется организацией устройства хранения. </WRAP> А теперь выполним поиск файлов по времени их последнего изменения. Этот подход можно использовать для создания резервных копий или организации файлов в хронологическом порядке. Для этого сначала создадим эталонный файл, время последнего изменения которого будет использоваться для сравнения:

touch playground/timestamp

Был создан пустой файл timestamp и установлено время его последнего изменения равным текущему времени. С помощью команда stat выводит всю информацию о файле и его атрибутах, которой обладает система:

stat playground/timestamp
  File: playground/timestamp
  Size: 0               Blocks: 0          IO Block: 4096   regular empty file
Device: 810h/2064d      Inode: 114840      Links: 1
Access: (0644/-rw-r--r--)  Uid: ( 1000/      nevvad)   Gid: ( 1000/      nevvad)
Access: 2021-06-09 12:35:24.926383200 +0300
Modify: 2021-06-09 12:35:24.926383200 +0300
Change: 2021-06-09 12:35:24.926383200 +0300
 Birth: -

Если применить команду touch к файлу еще раз и затем исследовать его с помощью stat, увидим, что время последнего его изменения обновилось:

touch playground/timestamp
stat playground/timestamp
  File: playground/timestamp
  Size: 0               Blocks: 0          IO Block: 4096   regular empty file
Device: 810h/2064d      Inode: 114840      Links: 1
Access: (0644/-rw-r--r--)  Uid: ( 1000/      nevvad)   Gid: ( 1000/      nevvad)
Access: 2021-06-09 12:40:57.716383200 +0300
Modify: 2021-06-09 12:40:57.716383200 +0300
Change: 2021-06-09 12:40:57.716383200 +0300
 Birth: -

Далее воспользуемся командой find, чтобы обновить время последнего изменения некоторых файлов в нашей песочнице:

find playground/ -type f -name "file-B" -exec touch '{}' ';'

Эта команда обновит время последнего изменения для всех файлов с именем file-B, имеющихся в песочнице. Теперь найдем с помощью find обновленные файлы, сравнив все файлы с эталонным файлом timestamp:

find playground/ -type f -newer playground/timestamp | wc -l
100

В результате мы получим все 100 файлов с именем file-B. Поскольку команда touch применялась ко всем файлам file-B в песочнице после обновления файла timestamp, они оказались «новее», чем timestamp, и потому были идентифицированы проверкой -newer

В заключение вернемся к проверке плохих разрешений, выполнявшейся выше, и применим ее к каталогу playground:

find playground \( -type f -not -perm 0600 \) -or \( -type d -not -perm 0700 \)

Эта команда выведет все 100 каталогов и 2600 файлов, хранящихся в playground (а также файл timestamp и сам каталог playground, всего 2702 элемента), потому что ни один из них не соответствует нашему определению «удовлетворительные разрешения». Вооружившись новыми знаниями об операторах и операциях, добавим в эту команду операции для применения новых разрешений к файлам и каталогам в песочнице:

find playground \( -type f -not -perm 0600 -exec chmod 0600 '{}' ';' \) -or \( -type d -not -perm 0700 -exec chmod 0700 '{}' ';' \)

Основываясь на повседневном опыте, следует отметить, что намного проще ввести две команды – одну для каталогов и одну для файлов, чем одну большую составную команду.

Параметры

Параметры помогают управлять областью поиска. Они могут включаться в выражения команды find наряду с другими проверками и операциями.
Наиболее часто используемые параметры команды find

Параметр Описание
-depth Требует от find обработать сначала файлы в каталогах и только потом каталоги. Этот параметр автоматически применяется с операцией -delete
-maxdepth число_уровней Устанавливает максимальное число уровней, на которое команда find может опускаться в дереве каталогов, выполняя проверки и операции
-mindepth число_уровней Устанавливает минимальное число уровней, на которое команда find должна опуститься в дереве каталогов перед выполнением проверок и операций
-mount Требует от find не выполнять обход каталогов, в которые смонтированы другие файловые системы
-noleaf Требует от find не оптимизировать поиск, опираясь на предположение, что поиск ведется в Unix-подобной файловой системе. Этот параметр необходимо использовать при обходе файловых систем DOS/Windows CD-ROM
find.txt · Last modified: 2023/04/06 10:28 (external edit)