Поиск по сайту:

Как использовать команду find в Linux


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

Команда поиска Linux

Команда Linux find является мощной и гибкой. Он может искать файлы и каталоги, используя множество различных критериев, а не только имена файлов. Например, он может искать пустые файлы, исполняемые файлы или файлы, принадлежащие конкретному пользователю. Он может находить и перечислять файлы по времени их доступа или изменения, вы можете использовать шаблоны регулярных выражений, он рекурсивен по умолчанию и работает с псевдофайлами, такими как именованные каналы (буферы FIFO).

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

Принцип передачи вывода одной команды в другую команду является основной характеристикой операционных систем, производных от Unix. Принцип разработки, заключающийся в том, что программа должна делать одну вещь и делать это хорошо, и ожидать, что ее выходные данные могут быть входными данными для другой программы, даже если она еще не написана, часто описывается как «философия Unix». И все же некоторые основные утилиты, такие как mkdir, не принимают ввод по конвейеру.

Чтобы устранить этот недостаток, можно использовать команду xargs для разделения входных данных по конвейеру и подачи их в другие команды, как если бы они были параметрами командной строки для этой команды. Этим достигается почти то же самое, что и прямым трубопроводом. Это «почти то же самое», а не «точно то же самое», потому что могут быть неожиданные различия с расширениями оболочки и подстановкой имен файлов.

Использование поиска с помощью xargs

Мы можем использовать find с xargs для некоторых действий, выполняемых над найденными файлами. Это многословный способ сделать это, но мы могли бы передать файлы, найденные с помощью find, в xargs , который затем передает их в tar для создания архивного файла этих файлов. Мы запустим эту команду в каталоге, в котором есть много файлов справочной системы PAGE.

find ./ -name "*.page" -type f -print0 | xargs -0 tar -cvzf page_files.tar.gz

Команда состоит из разных элементов.

  • find ./ -name «*.page» -type f -print0:  Действие поиска начнется в текущем каталоге с поиска по имени файлов, соответствующих запросу «*.page». нить. Каталоги не будут перечислены, потому что мы специально указываем искать только файлы с помощью -type f. Аргумент print0 указывает find не рассматривать пробелы как конец имени файла. Это означает, что имена файлов с пробелами в них будут обработаны правильно.
  • xargs -o-0 аргументы xargs не рассматривать пробелы как конец имени файла.
  • tar -cvzf page_files.tar.gz: это команда xargs, которая будет передавать список файлов из find в. Утилита tar создаст архивный файл с именем «page_files.tar.gz».

Мы можем использовать ls, чтобы увидеть файл архива, созданный для нас.

ls *.gz

Архивный файл создан для нас. Чтобы это работало, все имена файлов должны быть переданы в tar массово, что и произошло. Все имена файлов были помечены в конце команды tar как очень длинная командная строка.

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

Эта команда передает сразу все имена файлов в wc. По сути, xargs создает длинную командную строку для wc с каждым из имен файлов в ней.

find . -name "*.page" -type f -print0 | xargs -0 wc

Строки, слова и символы для каждого файла печатаются вместе с общим количеством для всех файлов.

Если мы используем опцию xarg  -I (заменить строку) и определим токен строки замены — в данном случае «{}» — token заменяется в финальной команде каждым именем файла по очереди. Это означает, что wc вызывается неоднократно, по одному разу для каждого файла.

find . -name "*.page" -type f -print0 | xargs -0 -I "{}" wc "{}"

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

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

Параметр find -exec

Команда find имеет встроенный метод вызова внешних программ для выполнения дальнейшей обработки имен файлов, которые она возвращает. Параметр -exec (выполнить) имеет синтаксис, аналогичный синтаксису команды xargs, но отличающийся от него.

find . -name "*.page" -type f -exec wc -c "{}" \;

Это подсчитает слова в соответствующих файлах. Команда состоит из этих элементов.

  • найти .: начать поиск в текущем каталоге. Команда find по умолчанию является рекурсивной, поэтому поиск будет выполняться и в подкаталогах.
  • -name «*.page»: мы ищем файлы с именами, соответствующими строке поиска «*.page».
  • -тип f: мы ищем только файлы, а не каталоги.
  • -exec wc: мы собираемся выполнить команду wc для имен файлов, соответствующих строке поиска.
  • -w: любые параметры, которые вы хотите передать команде, должны располагаться сразу после команды.
  • {}: заполнитель {} представляет каждое имя файла и должен быть последним элементом в списке параметров.
  • \;: точка с запятой «;» используется для обозначения конца списка параметров. Он должен быть экранирован обратной косой чертой «\», чтобы оболочка не интерпретировала его.

Когда мы запускаем эту команду, мы видим вывод wc. -c (количество байтов) ограничивает его вывод количеством байтов в каждом файле.

Как видите, суммы нет. Команда wc выполняется один раз для каждого имени файла. Заменив знак «плюс» «+» на завершающую точку с запятой «;», мы можем изменить поведение -exec, чтобы он работал со всеми файлами в один раз.

find . -name "*.page" -type f -exec wc -c "{}" \+

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

exec на самом деле означает exec

Параметр -exec (выполнить) не запускает команду, выполняя ее в текущей оболочке. Он использует встроенный в Linux exec для запуска команды, заменяя текущий процесс — вашу оболочку — командой. Таким образом, запускаемая команда вообще не выполняется в оболочке. Без оболочки вы не можете получить расширение оболочки подстановочных знаков, и у вас нет доступа к псевдонимам и функциям оболочки.

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

function words-only () 
{ 
  wc -w $1
}

Возможно, странная функция, «только слова» намного длиннее для ввода, чем «wc -w», но, по крайней мере, это означает, что вам не нужно запоминать параметры командной строки для wc. Мы можем проверить, что он делает следующим образом:

words-only user_commands.pages

Это прекрасно работает с обычным вызовом командной строки. Если мы попытаемся вызвать эту функцию, используя параметр find -exec, это не удастся.

find . -name "*.page" -type f -exec words-only "{}" \;

Команде find не удается найти функцию оболочки, а действие -exec не выполняется.

Чтобы преодолеть это, мы можем запустить find оболочку Bash и передать ей остальную часть командной строки в качестве аргументов оболочки. Нам нужно заключить командную строку в двойные кавычки. Это означает, что нам нужно избегать двойных кавычек вокруг строки замены «{}».

Прежде чем мы сможем запустить команду find, нам нужно экспортировать нашу функцию оболочки с опцией -f (как функцию):

export -f words-only
find . -name "*.page" -type f -exec bash -c "words-only \"{}\"" \;

Это работает, как и ожидалось.

Использование имени файла более одного раза

Если вы хотите связать несколько команд вместе, вы можете сделать это и использовать строку замены «{}» в каждой команде.

find . -name "*.page" -type f -exec bash -c "basename "{}" && words-only "{}"" \;

Если мы cd выйдем на уровень вверх из каталога «pages» и запустим эту команду, find все равно обнаружит файлы PAGE, потому что поиск выполняется рекурсивно. Имя файла и путь передаются нашей функции только слова, как и раньше. Исключительно для демонстрации использования -exec с двумя командами мы также вызываем команду basename, чтобы увидеть имя файла без пути.

И команда basename, и функция оболочки только слова имеют имена файлов, переданные им с помощью строки замены «{}».

Лошади для курсов

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

Но иногда — в зависимости от того, чего вы пытаетесь достичь — у вас может не быть другого выбора. Какой бы метод ни требовался в вашей ситуации, никого не должно удивлять, что Linux предоставляет достаточно вариантов, чтобы вы могли найти тот, который соответствует вашим конкретным потребностям.