Поиск в Linux с помощью команды find
Общий синтаксис
find <где искать> <опции>
<где искать> — путь к корневому каталогу, откуда начинать поиск. Например, find /home/user — искать в соответствующем каталоге. Для текущего каталога нужно использовать точку «.».
<опции> — набор правил, по которым выполнять поиск.
** по умолчанию, поиск рекурсивный. Для поиска в конкретном каталоге можно использовать опцию maxdepth.*
Описание опций
| Опция | Описание |
|---|---|
| -name | Поиск по имени. |
| -iname | Регистронезависимый поиск по имени. |
| -type | Тип объекта поиска. Возможные варианты: |
- f — файл;
- d — каталог;
- l — ссылка;
- p — pipe;
- s — сокет. |
| -size | Размер объекта. Задается в блоках по 512 байт или просто в байтах (с символом «c»). | | -mtime | Время изменения файла. Указывается в днях. | | -mmin | Время изменения в минутах. | | -atime | Время последнего обращения к объекту в днях. | | -amin | Время последнего обращения в минутах. | | -ctime | Последнее изменение владельца или прав на объект в днях. | | -cmin | Последнее изменение владельца или прав в минутах. | | -user | Поиск по владельцу. | | -group | По группе. | | -perm | С определенными правами доступа. | | -depth | Поиск должен начаться не с корня, а с самого глубоко вложенного каталога. | | -maxdepth | Максимальная глубина поиска по каталогам. -maxdepth 0 — поиск только в текущем каталоге. По умолчанию, поиск рекурсивный. | | -prune | Исключение перечисленных каталогов. | | -mount | Не переходить в другие файловые системы. | | -regex | По имени с регулярным выражением. | | -regextype | Тип регулярного выражения. | | -L или -follow | Показывает содержимое символьных ссылок (симлинк). | | -empty | Искать пустые каталоги. | | -delete | Удалить найденное. | | -ls | Вывод как ls -dgils | | -print | Показать найденное. | | -print0 | Путь к найденным объектам. | | -exec {} ; | Выполнить команду над найденным. | | -ok | Выдать запрос перед выполнением -exec. |
Также доступны логические операторы:
| Оператор | Описание |
|---|---|
| -a | Логическое И. Объединяем несколько критериев поиска. |
| -o | Логическое ИЛИ. Позволяем команде find выполнить поиск на основе одного из критериев поиска. |
| -not или ! | Логическое НЕ. Инвертирует критерий поиска. |
Полный набор актуальных опций можно получить командой **man find**.
Примеры использования find
Поиск файла по имени
1. Простой поиск по имени:
find / -name "file.txt"
** в данном примере будет выполнен поиск файла с именем file.txt по всей файловой системе, начинающейся с корня /.*
2. Поиск файла по части имени:
find / -name "*.tmp"
** данной командой будет выполнен поиск всех папок или файлов в корневой директории /, заканчивающихся на .tmp*
3. Несколько условий.
а) Логическое И. Например, файлы, которые начинаются на **sess_** и заканчиваются на **cd**:
find . -name "sess_*" -a -name "*cd"
б) Логическое ИЛИ. Например, файлы, которые начинаются на **sess_** или заканчиваются на **cd**:
find . -name "sess_*" -o -name "*cd"
в) Более компактный вид имеют регулярные выражения, например:
find . -regex '.*/\(sess_.*cd\)'
find . -regex '.*/\(sess_.*\|.*cd\)'
** где в первом поиске применяется выражение, аналогичное примеру а), а во втором — б).*
Будте аккуратнее при использовании условий, так как они отделяют одну часть опций, от другой. Например:
find ./ -name 1 -o -name 2 -type f
... будет искать либо все с именем 1, либо только файлы с именем 2 (опция **-type f** находится после **-o** справа). Если нужны файлы с именем 1 или 2, то используем скобки:
find ./ \( -name 1 -o -name 2 \) -type f
** Обратите внимание, что скобки должны быть заэкранированы, а также должен быть пробельный отступ внутри скобок.*
4. Найти все файлы, кроме .log:
find . ! -name "*.log"
** в данном примере мы воспользовались логическим оператором !.*
Поиск по дате
1. Поиск файлов, которые менялись определенное количество дней назад:
find . -type f -mtime +60
** данная команда найдет файлы, которые менялись более 60 дней назад.*
Или в промужутке:
find . -mmin -20 -mmin +10 -type f
** найти все файлы, которые менялись более 10 минут, но не более 20-и.*
2. Поиск файлов с помощью **newer**. Данная опция доступна с версии 4.3.3 (посмотреть можно командой **find --version**).
а) дате изменения:
find . -type f -newermt "2019-11-02 00:00"
** покажет все файлы, которые менялись, начиная с 02.11.2019 00:00.*
find . -type f -newermt 2019-10-31 ! -newermt 2019-11-02
** найдет все файлы, которые менялись в промежутке между 31.10.2019 и 01.11.2019 (включительно).*
б) дате обращения:
find . -type f -newerat 2019-10-08
** все файлы, к которым обращались с 08.10.2019.*
find . -type f -newerat 2019-10-01 ! -newerat 2019-11-01
** все файлы, к которым обращались в октябре.*
в) дате создания:
find . -type f -newerct 2019-09-07
** все файлы, созданные с 07 сентября 2019 года.*
find . -type f -newerct 2019-09-07 ! -newerct "2019-09-09 07:50:00"
* *файлы, созданные с 07.09.2019 00:00:00 по 09.09.2019 07:50*
Или можно найти все файлы, созданные за сегодняшний день:
find ./ -newerct 'yesterday'
По типу
1. Искать в текущей директории и всех ее подпапках только файлы:
find . -type f
** f — искать только файлы.*
2. Найти только директории:
find . -type d
** d — искать только папки.*
3. Найти исполняемые (бинарные) файлы.
У find нет опции для поиска бинарных файлов, но мы можем передать результат поиска команде **grep -IL** с помощью **exec** (подробнее [рассмотрен ниже](#actions)):
find / -name openssl -type f -exec grep -IL . "{}" \;
** в данном примере мы найдем в системе все файлы с именем openssl, которые являются исполняемыми.*
Поиск по правам доступа
1. Ищем все справами на чтение и запись:
find / -perm 0666
2. Находим файлы, доступ к которым имеет только владелец:
find / -perm 0600
Поиск файла по содержимому
find / -type f -exec grep -i -H "content" {} \;
** в данном примере выполнен рекурсивный поиск всех файлов в директории / и выведен список тех, в которых содержится строка content.*
С сортировкой по дате модификации
find /data -type f -printf '%TY-%Tm-%Td %TT %p\n' | sort -r
** команда найдет все файлы в каталоге /data, добавит к имени дату модификации и отсортирует данные по имени. В итоге получаем, что файлы будут идти в порядке их изменения.*
Или попроще с использованием ls:
find /data -type f | ls -1t
или в обратном порядке:
find /data -type f | ls -1tr
Лимит на количество выводимых результатов
Самый распространенный пример — вывести один файл, который последний раз был модифицирован. Берем пример с сортировкой и добавляем следующее:
find /data -type f -printf '%TY-%Tm-%Td %TT %p\n' | sort -r | head -n 1
Поиск с действием (exec)
1. Найти только файлы, которые начинаются на *sess_* и удалить их:
find . -name "sess_*" -type f -print -exec rm {} \;
** -print использовать не обязательно, но он покажет все, что будет удаляться, поэтому данную опцию удобно использовать, когда команда выполняется вручную.*
2. Переименовать найденные файлы:
find . -name "sess_*" -type f -exec mv {} new_name \;
или:
find . -name "sess_*" -type f | xargs -I '{}' mv {} new_name
3. Переместить найденные файлы:
find . -name "sess_*" -type f -exec mv {} /new/path/ \;
** в данном примере мы переместим все найденные файлы в каталог /new/path/.*
4. Вывести на экран количество найденных файлов и папок, которые заканчиваются на *.tmp*:
find . -name "*.tmp" | wc -l
5. Изменить права.
Рассмотрим пример, как найти все папки и задать им определенные права:
find /home/user/* -type d -exec chmod 2700 {} \;
** в данном примере мы ищем все каталоги (type d) в директории /home/user и ставим для них права 2700.*
Или так можно изменить права для всех файлов и каталогов:
find ./ -type f -exec chmod 0644 {} \;
** в данном примере мы ищем все файлы (type f) в текущей директории ./ и ставим для них права 0644.*
find ./ -type d -exec chmod 0755 {} \;
** в данном примере мы ищем все папки (type d) в текущей директории ./ и ставим для них права 0755.*
6. Передать найденные файлы конвееру (pipe):
find /etc -name '*.conf' -follow -type f -exec cat {} \; | grep 'test'
** в данном примере мы использовали find для поиска строки test в файлах, которые находятся в каталоге /etc, и название которых заканчивается на .conf. Для этого мы передали список найденных файлов команде grep, которая уже и выполнила поиск по содержимому данных файлов.*
7. Произвести замену в файлах с помощью команды sed:
find /opt/project -type f -exec sed -i -e "s/test/production/g" {} \;
** находим все файлы в каталоге /opt/project и меняем их содержимое с test на production.*
8. Выполнить несколько команд можно с помощью нескольких вызовов exec:
find ./ -type d -exec chmod 0755 {} \; -exec chown dmosk {} \;
** в итоге, первая команда будет назначать права 0755, а вторая — задавать владельца dmosk.*
Чистка по расписанию
Команду **find** удобно использовать для автоматического удаления устаревших файлов.
Открываем на редактирование задания cron:
crontab -e
И добавляем:
0 0 * * * /bin/find /tmp -mtime +14 -exec rm {} \;
** в данном примере мы удаляем все файлы и папки из каталога /tmp, которые старше 14 дней. Задание запускается каждый день в 00:00.
* полный путь к исполняемому файлу find смотрим командой **which find** — в разных UNIX системах он может располагаться в разных местах.*
Поиск файлов с помощью bat в любом месте
Чтобы найти все файлы в любом месте внутри, `/path/to/folder` имена которых содержат `bat`, вы можете использовать:
find /path/to/folder -name '*bat*'
Я [заключил в кавычки](https://gnu.org/software/bash/manual/bash.html#Quoting) шаблон поиска `*bat*` потому, что, если бы кавычки были опущены и файлы, соответствующие `*bat*` в текущем каталоге, были бы перечислены, оболочка превратила бы `*bat*` в их список и передала *его* в `find`. Тогда `find` не работало бы должным образом. (`\*bat\*` и `"*bat*"` тоже работают.)
Чтобы выполнить поиск в папке, в которой вы находитесь в данный момент (например, в той, в которую вы `cd` перешли), используйте `.`, как обычно:
find . -name '*bat*'
Чтобы выполнить поиск по всему компьютеру, [используйте `/`](https://en.wikipedia.org/wiki/Root_directory). Чтобы выполнить поиск по домашнему каталогу, используйте `~` или полное имя вашего домашнего каталога. ([Оболочка расшифровывает `~`](https://gnu.org/software/bash/manual/bash.html#Tilde-Expansion) до полного пути к вашему домашнему каталогу.)
Расширение или сужение вашего поиска В зависимости от названия
Если вы хотите выполнять поиск без учёта регистра, чтобы файлы, содержащие `BAT`, `bAt`, и так далее, совпадали, используйте тест `-iname` вместо теста `-name`.
find /path/to/folder -iname '*bat*'
Я заметил, что все ваши файлы заканчиваются на `.c`. Если вы хотите найти только такие файлы, используйте:
find /path/to/folder -name '*bat*.c'
Я заметил, что во всех ваших именах файлов `bat` находится либо в самом начале, либо в самом конце части, предшествующей суффиксу `.c`. Если вы хотите избежать совпадения с файлами, подобными `embattled.c`, вы можете использовать:
find /path/to/folder -name '*bat.c' -o -name 'bat*.c'
-o является оператором или.
Только Совпадающие файлы
Чтобы найти только [*обычные файлы*](https://en.wikipedia.org/wiki/Unix_file_types#Regular_file), а не папки, символические ссылки и специальные узлы устройств, вы можете использовать `-type f`. Это часто рекомендуется и иногда вполне уместно... но **часто это не то, что вам нужно**, особенно если вы запускаете `find` для самостоятельного изучения результатов. Если бы у вас была [символическая ссылка](https://en.wikipedia.org/wiki/Symbolic_link), соответствующая вашему запросу, разве вы не хотели бы узнать о ней?
Если вы хотите найти как обычные файлы, так и символические ссылки, вы можете использовать:
find /path/to/folder -name '*bat*' \( -type f -o -type l \)
Для этого используется оператор `-o` и скобки для группировки (которые должны быть заключены в кавычки, чтобы оболочка не обрабатывала их особым образом; в противном случае вы получите синтаксическую ошибку).
Но предположим, что вы хотите видеть только символические ссылки, которые в конечном итоге указывают на обычный файл (а не на символические ссылки на каталоги, узлы устройств и т. д.). На самом деле это ещё проще: используйте `-xtype` вместо `-type`. Если вы не запускаете `find` с флагом `-L`, `-xtype` для символической ссылки проверяет тип файла, на который указывает ссылка.
find /path/to/folder -name '*bat*' -xtype f
Если у вас есть символическая ссылка на другую символическую ссылку на файл, `-xtype f` будет соответствовать ей, даже если её *прямой* целью является другая символическая ссылка, а не обычный файл. Это почти всегда то, что вам нужно.
Часто люди думают, что хотят `-type f`, но на самом деле они хотят `-xtype f`.
Получение подробных выходных данных
findЕсли вы не укажете действие по умолчанию, оно будет равно -print. Все приведённые выше команды эквивалентны самим себе с добавленным в конце -print
find часто используется для запуска команд на основе найденных файлов — часто это команды, которые вносят изменения. Но есть и другие действия, целью которых является отображение результатов, помимо -print. Особый интерес представляет -ls:
find /path/to/folder -name '*bat*' -ls
Это даёт подробную информацию о каждом файле в формате с несколькими столбцами, похожем на (хотя и не совсем таком же, как) то, что вы увидите при запуске `ls *file*`.