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

Она используется для поиска файлов и папок через командную строку Linux.

Команда find — одна из самых мощных и широко применимых команд. При этом она крайне объёмная и насчитывает более 50 опций, в которых легко запутаться, особенно в сочетании с командами exec или xargs.

Если вы сисадмин или разработчик, избежать команды find при работе с командной строкой не получится. Так что давайте научимся её не бояться и пользоваться её возможностями в полной мере.

Для этого разберём самые распространённые случаи практического применения команды find. Но для начала покажу вам синтаксис и принцип работы с командой.

Команда find в Linux


Общий синтаксис команды find выглядит так:

find [directory to search] [options] [expression]

Всё, что в квадратных скобках, указывать необязательно. А значит, выполнить команду find можно вообще без опций и параметров. Она выдаст список всех файлов и папок в текущем расположении. Мало полезного, да?

Так что давайте взглянем на параметры подробнее:

  • directory to search (папка поиска) — это расположение, с которого вы хотите начать поиск. Поиск по умолчанию рекурсивный и начинается с текущего расположения.
  • options (опции) содержит указание типа поиска: по имени, типу файла, времени изменения и так далее — тут может быть более 50 вариантов.
  • expression (выражение) содержит поисковый запрос. Если вы ищете файл по имени, параметр expression должен содержать имя файла. Если ищете файлы с именем, соответствующим заданному шаблону, поисковое выражение — это шаблон.

Приведу простой пример:

find . -type f -name myfile

Такая команда выполнит поиск файла (именно файла, не папки) с именем myfile в текущей папке и подпапках. Опция -type f сужает поиск до файлов. Точка (.) указывает на текущую папку.

Рассмотрим несколько примеров применения команды find.

Поиск файлов и папок по имени


Так выполняется поиск файлов и папок по имени:

find . -name SEARCH_NAME

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

Пример ниже — поиск файлов и папок с именем «mystuff»:

abhishek@LHB:~/Examples$ find -name mystuff
./new/mystuff
./mystuff

Поиск только файлов или только папок


Если нужно искать только файлы, на помощь придёт опция type -f:

find . -type f -name SEARCH_NAME

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

abhishek@LHB:~/Examples$ find -type f -name mystuff
./mystuff

Если нужно найти папку, укажите тип type -d:

find . -type d -name SEARCH_NAME

Вот пример нашего поиска уже по папкам:

abhishek@LHB:~/Examples$ find -type d -name mystuff
./new/mystuff

Поиск без учёта регистра


Команда find по умолчанию учитывает регистр. Чтобы выполнить поиск по имени файла без учёта регистра, надо ввести опцию -iname вместо -name.

find . -type f -iname SEARCH_NAME

С поиском по папкам (type -d) это тоже работает.

abhishek@LHB:~/Examples$ find -iname mystuff
./new/mystuff
./MyStuff
./mystuff

Скриншот последних трёх примеров:

image

Поиск файлов по расширению (важно)


Одно из самых популярных применений команды find — поиск файлов определённого типа, то есть по заданному расширению.

Скажем, вы хотите найти все файлы С++ в текущих папках. Файлы С++ имеют расширение .cpp, и вот как их можно найти:

find . -type f -name "*.cpp"

С такими опциями команда find найдёт только файлы (-type f) с именами, оканчивающимися на .cpp.

abhishek@LHB:~$ find . -type f -name "*.cpp"
./file.cpp
./.cargo/registry/src/github.com-1ecc6299db9ec823/libz-sys-1.1.3/src/zlib/contrib/iostream2/zstream_test.cpp
./.cargo/registry/src/github.com-1ecc6299db9ec823/libz-sys-1.1.3/src/zlib/contrib/iostream/test.cpp
./.cargo/registry/src/github.com-1ecc6299db9ec823/libz-sys-1.1.3/src/zlib/contrib/iostream/zfstream.cpp

При работе с командой find всегда заключайте поисковое выражение в двойные кавычки.

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

Вот что будет, если ввести запрос без кавычек:

find . -type f -name *.cpp

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

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

image

В нашем случае файл .cpp всего один, и после подстановки команда выглядит так: find . -type f -name file.cpp. Она работает, поскольку file.cpp — корректный поисковый запрос.

А вот файлов .txt в той же папке два, и когда команда расширяется до find . -type f -name another.txt new.txt, выводится предупреждение, потому что поисковых запросов больше одного.

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

Поиск нескольких файлов с несколькими расширениями (или условием)


Команда, рассмотренная выше, нужна для поиска файлов по расширению. А что если нужно найти файлы с несколькими разными расширениями?

Вместо того чтобы прогонять команду find несколько раз, введите её один раз с опцией -o, которая работает как логическое условие «или»:

find . -type f -name "*.cpp" -o -name "*.txt" 

Например:

abhishek@LHB:~/Examples$ find . -type f -name "*.txt" -o -name "*.cpp"
./new.txt
./file.cpp
./new/new.txt
./new/dir2/another.txt
./new/dir1/new.txt
./another.txt

Поиск файлов в заданной папке


Все приведённые примеры иллюстрируют поиск в текущей папке, потому что команда включает в себя точку (.).

Чтобы выполнить поиск в заданной папке, не покидая текущего расположения, можно заменить точку абсолютным или относительным путём к нужной папке.

abhishek@LHB:~/Examples$ find ./new -name mystuff
./new/mystuff

Поиск файлов в нескольких папках


Если нужные вам файлы могут находиться в нескольких папках, можно выполнить поиск во всех этих расположениях за один раз. Просто укажите все пути к папкам при введении команды find:

find ./location1 /second/location -type f -name "pattern"

Поиск пустых файлов и папок


Опция -empty позволяет использовать команду find для поиска пустых файлов и папок.

Найти таковые в текущей папке можно следующим образом:

find . -empty

Можно указать тип объектов, чтобы искать только файлы или только папки:

find . -empty -type f

Кроме того, можно в таком режиме искать файлы по имени:

find . -empty -type f -name "*.cpp"

image

Поиск крупных и мелких файлов (поиск по размеру файла)


Команда find поможет найти крупные или мелкие файлы, если выполнить поиск по размеру. Но это работает только для файлов, не для папок.

Используется опция -size с аргументом +N для файлов размером более N и -N для файлов размером менее N.

А вот как можно найти файлы точного заданного размера (50 КБ):

find . -size 50k

Так выполняется поиск файлов размером более 1 ГБ в текущей папке:

find . -size +1G

А так — файлов, не превышающих 20 байт:

find . -size -20c

Для поиска файлов размером более 100 МБ, но менее 2ГБ, введите:

find . -size +100M -size -2G

Поиск по размеру тоже можно сочетать с поиском по имени файла. Таким образом, найти в корневом каталоге все файлы размером более 500 МБ с именем, оканчивающимся на .log, можно так:

find / -size +500M -name "*.log"

Для справки:

  • c – байты
  • k – килобайты
  • M – мегабайты
  • G – гигабайты

Поиск недавно изменённых файлов (поиск по времени изменения или создания)


Вы ведь знакомы с параметрами mtime, atime и ctime?

  • Mtime – время последнего изменения файла
  • Ctime – время создания файла
  • Atime – время последнего доступа к файлу

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

Найти все файлы, претерпевшие изменения за последние трое суток (3*24ч), можно так:

find . -type f -mtime -3

А все файлы, созданные пять и более дней назад, ищутся так:

find . -type f -ctime +5

Понимаю, что 24 часа — большой срок. Что если нужно выявить файлы, изменённые всего пару минут назад? Для этого предусмотрены опции mmin, amin и cmin.

Так выглядит команда поиска всех файлов, изменённых за последние пять минут:

find . -type f -mmin -5

image

Можно не только указать имя файла, но и ограничить временной промежуток с двух сторон. Команда ниже выполнит поиск всех файлов .java, изменённых не ранее 30 и не позднее 20 минут назад.

find . -type f -mmin +20 -mmin -30 -name "*.java"

Поиск файлов с определёнными настройками доступа


Надеюсь, вы имеете представление о разрешениях файлов в Linux.

Команда find позволяет выполнить поиск файлов по разрешению и режиму доступа.

find -perm mode

Поищем в текущей папке, к примеру, все файлы с режимом доступа 777:

find . -perm 777

А так можно найти все файлы с правами на чтение и запись для всех типов пользователей (только точное совпадение; файлы с правами на выполнение для всех не отобразятся):

find . -perm a=r+w

Поиск файлов по владельцу


Можно также найти файлы, принадлежащие определённому пользователю.

Вот как обнаружить в текущей папке все файлы пользователя Джона:

find . -type f -user John

Эта опция сочетается с другими, будь то размер или время и имя файла:

find . -type f -user John -name "*.cpp"

Отключение рекурсивного поиска для поиска только в текущей папке


По умолчанию команда find выполняет поиск во всех подпапках текущего расположения. Если это не требуется, можно ограничить глубину поиска значением «1». Так вы ограничитесь поиском в текущей папке, не залезая в подпапки.

find . -maxdepth 1 -type f -name "*.txt"

image

Исключение папки из поиска


Если нет необходимости производить поиск в той или иной папке, можно исключить её с помощью опций path, prune и логического «или».

find . -path "./directory_exclude/*" -prune -o -name SEARCH_NAME

Будьте внимательны: путь к папке должен оканчиваться на *, затем идёт -prune и только потом -o.

Попросту говоря, при поиске с опцией prune папка, указанная с помощью path, игнорируется. Prune всегда сопровождается флагом -o (логическое «или»), чтобы папки, которые не были исключены, просматривались на наличие искомого объекта.

Дальнейшая работа с результатами команды find: exec и xargs


Итак, мы изучили различные способы поиска файлов по заданным параметрам. Это хорошо. А теперь следующий шаг: рассмотрим, какие действия можно выполнять с результатами команды find.

Например, как найти файлы с именем, соответствующим определённому шаблону, и переименовать их за одно действие? Или выявить и удалить пустые файлы?

Вам уже известно, что в Linux можно использовать перенаправление ввода-вывода, чтобы объединить результаты одной команды с вводом другой. Но с результатами команды find это не сработает — по крайней мере, не напрямую.

Чтобы выполнить действия над результатом команды find, есть два варианта:

  • Применить exec
  • Применить xargs

Использование find и exec


Допустим, вам нужен подробный список (ls -l) файлов, найденных командой find. Вот как его получить:

find . -type f -name *.txt" -exec ls -l {} +

Результат будет таким:

abhishek@LHB:~/Examples$ find . -type f -name "*.txt" -exec ls -l {} +
-rw-rw-r-- 1 abhishek abhishek 39 Oct 13 19:30 ./another.txt
-rw-rw-r-- 1 abhishek abhishek 35 Oct 13 15:36 ./new/dir1/new.txt
-rw-rw-r-- 1 abhishek abhishek 35 Oct 13 15:36 ./new/dir2/another.txt
-rw-rw-r-- 1 abhishek abhishek 35 Oct 13 18:51 ./new/mystuff/new.txt
-rwxrwxrwx 1 abhishek abhishek 35 Oct 13 15:37 ./new/new.txt
-rw-rw-r-- 1 abhishek abhishek 35 Oct 13 18:16 ./new.txt

Многие забывают ввести {} + в конце команды exec. Но это необходимо — как и пробел между скобками {} и плюсом +.

Фигурные скобки ссылаются на результат выполнения команды find. Их содержимое может иметь следующий вид: {файл 1, файл 2, файл 3}. Символ + используется как конец команды exec.

Есть ещё один вариант оформления exec:

find . -type f -name *.txt" -exec ls -l {} \;

В данном случае плюс заменён на точку с запятой. Дополнительная косая черта означает, что точка с запятой не является специальным символом.

Преимущество сочетания {} + заключается в меньшем количестве команд ( ls -l file1 file2 file3), тогда как комбинация {} \; запустит цепочку ls -l file1, ls -l file2 и так далее.

Однако сочетание {} \; даёт возможность использовать {} несколько раз в одном и том же выражении exec. Так, приведённая ниже команда переименует все обнаруженные файлы с расширением .old.

find . -type f -name *.txt" -exec mv {} {}.old \;

Использование команды xargs


Многие пользователи Linux сталкиваются с необходимостью перенаправления ввода-вывода довольно часто. Но команда exec с цепочкой символов {} + кажется им слишком сложной.

И тут на помощь приходит xargs. Нужно просто перенаправить вывод команды find в команду xargs через конвейер.

find . -type f -name *.txt" | xargs ls -l

image

Синтаксис куда проще, верно? К тому же команда xargs тоже весьма эффективна. Подробнее о ней — в статье по ссылке.

Сочетание команд find и grep


Теперь вы умеете совмещать команду find с xargs и exec, и пора перейти на следующий уровень — объединить find и grep.

Для сисадминов и разработчиков комбинация команд find и grep — одна из самых распространённых и вместе с тем самых полезных.

Команда find находит файлы с именем, соответствующим шаблону, а затем команда grep выполняет поиск по их содержимому.

Например, вам нужно найти все файлы .txt, в которых есть имя «Alice». Объединить команды find и grep можно так:

find . -type f -name "*.txt" -exec grep -i alice {} +

А можно с помощью xargs:

find . -type f -name "*.txt" | xargs grep -i alice

image

Конечно, пример элементарный, но если команда grep вам знакома, можете использовать её на своё усмотрение.

И это далеко не все возможности команды find...


Перечислить все опции и примеры использования команды find практически невозможно. Её возможностям нет границ, но если вы освоите её принципы, она окажется очень кстати во многих ситуациях. Решающий фактор — как сочетается логика действия разных опций и команд.

Надеюсь, моя подборка примеров использования find была для вас полезна. Если у вас есть вопросы или предложения, как сделать эту статью лучше, добро пожаловать в комментарии.



НЛО прилетело и оставило здесь промокоды для читателей нашего блога:

15% на все тарифы VDS (кроме тарифа Прогрев) — HABRFIRSTVDS.

20% на выделенные серверы AMD Ryzen и Intel Core HABRFIRSTDEDIC.

Доступно до 31 декабря 2021 г.

Комментарии (8)


  1. dlinyj
    15.12.2021 13:17
    +1

    На самом деле, вроде такая мимоходная заметка, но команда find чуть ли не самая используемая мной команда в моей работе. Спасибо за статью!


  1. QtRoS
    15.12.2021 13:27

    Намного больше люблю такие статьи, чем man'ы, кладу в закладки. Спасибо!


    1. zorn-v
      15.12.2021 21:27
      +2

      Зря. Лучше научитесь пользоваться поиском по ману и сами начнете такие писать )


  1. maledog
    15.12.2021 14:31
    +2

    При поиске файлов по расширениям не учли, что эти файлы могли быть созданы в операционных системах в которых регистр не имеет значения. Например в windows. Потому -name "*.txt" лучше заменить на -iname "*.txt". Тогда будет искать и "*.txt" и "*.TXT" и "*.tXt"


  1. hard_sign
    16.12.2021 09:27
    +3

    find . -type f -name "*.cpp" -o -name "*.txt"

    Здесь ошибка. Эта команда ищет файлы *.cpp и любые объекты *.txt (ваше счастье, что у вас нет таких каталогов). Условия с OR надо заключать в скобки. А поскольку у bash свой взгляд на скобки, их надо ещё и экранировать:

    find . -type f \( -name "*.cpp" -o -name "*.txt" \)


  1. bbc_69
    16.12.2021 09:37
    +2

    Я бы добавил, что выражения в find - обычные булевы операции. При этом -o - это -or, a -and - это -a или его можно вообще опустить.

    Т.е. можно написать что-то вроде:

    find . -type d -name config -or -type f -name "*.cfg"

    И пример с грепом можно переписать в виде:

    find . -name "*alice*" -name "*.txt"

    -not тоже присутствует. Про скобочки написали выше.

    Моя любимая команда - такую гибкость использования ещё поискать надо.

    ЗЫ Ну и куда без ... -empty -delete?


    1. kilgur
      16.12.2021 19:36

      Греп же в примерах ищет не в имени, а в содержимом


      1. bbc_69
        16.12.2021 22:07

        Точно! Не обратил внимания на xargs.