Расширенная замена для UNIX/GNU «найти» (поиск файлов из командной строки)

смхайдрих

Расширенная замена для UNIX/GNU «найти» (поиск файлов из командной строки)

Утилита GNU по умолчанию для поиска файлов для командной строки findимеет массу опций, но по-прежнему не хватает некоторых, на мой взгляд, важных функций, таких как сортировка . Это также хлопотно использовать иногда.

Точно так же, как это ackможно рассматривать как современную расширенную версию grepс более чистым интерфейсом, может ли кто-нибудь порекомендовать аналогичную замену для find?

(Бонусные баллы, если он также имеет функциональность, аналогичную locate, то есть индексированный поиск.)

Тотти

Что насчет графического интерфейса? , поиск обезьяны ?

смхайдрих

@totti Я бы предпочел терминальные приложения, потому что они обычно позволяют быстро обрабатывать полученные результаты (например, дополнительная фильтрация через sed, интеграция в скрипт и т. д.). Но спасибо за ваше предложение, я тоже посмотрю на это.

Xen2050

Для графического интерфейса catfish работает нормально, хотя я не уверен в фильтрации sed. Но с обычным find вы всегда можете | sort, он может даже обрабатывать имена с завершением NUL с помощью--files0-from=-

Жиль "ТАК - перестань быть злым"

Воспользуйтесь оболочкой! Хотя ни одна оболочка не может сравниться findс расширенными вариантами использования , zsh может справиться со многими, и даже bash может справиться с базовыми.

Фундаментальной особенностью findявляется рекурсивный обход каталогов. Эта функция есть в современных интерактивных оболочках. В bash, ksh93, zsh и fish шаблон glob ** обозначает подкаталог на любой глубине. Таким образом, echo **/*перечисляются те же файлы, что и find .(за исключением того, что **/*файлы с точками по умолчанию пропускаются), echo **/*.txtперечисляются те же файлы find -name '*.txt, что и и т. д. Все оболочки сортируют совпадения с подстановочными знаками. Чтобы запустить команду, вы просто передаете ей аргументы, как обычно: вместо find -name '*.txt' -exec ls -ld {} +, вы можете просто запустить ls -ld **/*.txt.

В bash **шаблон должен быть включен с помощью shopt -s globstar. Поместите эту строку в свой ~/.bashrc. В ksh93 **шаблон должен быть включен с помощью set -o globstar. В fish и zsh всегда **включен.

Синтаксис оболочки более прост, когда вы хотите выполнить команду над файлами. Если вы хотите перечислить имена файлов, echoразделите их пробелами. Если вам нужен один файл в строке, вы можете использовать

printf '%s\n' **/*

Это немного громоздко вводить, но вы можете определить псевдоним, например

alias p='printf %s\\n'

Ksh определяет дополнительный синтаксис шаблона подстановочных знаков, который дает совпадению с подстановочными знаками ту же выразительную силу, что и регулярное выражение, а также ярлык для отрицания. В bash эти шаблоны можно включить с помощью shopt -s extglob; в зш, с setopt ksh_glob. В Zsh есть дополнительные операторы с такой же выразительной силой, которые необходимо активировать с помощью setopt extended_glob(вставьте setopt extended_globв свой ~/.zshrc). Вот несколько примеров дополнительных шаблонов zsh (многие из них требуют setopt extended_glob):

  • *-<8-15>.txt— сопоставлять файлы с числовым индексом от 8 до 15, за которым следует .txt. Например, это включает foo-8.txtи, foo-08.txtно не foo-100.txtили foo-a.txt. Ничего подобного в find.
  • *.txt~foo.txt— соответствует всем .txtфайлам, кроме foo.txt. Как find -name '*.txt' ! -name foo.txt.
  • *.(cc|cxx)— матч .ccи .cxxфайлы. Как find \( -name '*.cc' -o -name '*.cxx' \).

Имейте в виду, что в bash ≤4.2 и fish **/проходят символические ссылки на каталоги (например find -L, ). Ksh93, bash ≥4.3 и zsh безопасны: **/только обход каталогов. В zsh ***/также проходит символические ссылки на каталоги.

В большинстве оболочек сопоставление подстановочных знаков основано только на имени файла. Единственный способ сопоставить файлы по типу — добавить /в конце шаблона, что ограничивает совпадения каталогами (включая символические ссылки). Zsh уникален тем, что предлагает способ сопоставления файлов по типу и другим метаданным: квалификаторы glob . Вы даже можете встроить произвольный код в квалификаторы glob, чтобы запустить код для фильтрации и перезаписи совпадений, хотя, когда все становится настолько сложным, синтаксис, возможно, хуже, чем find. Вот несколько примеров простого использования квалификаторов glob. Напомним, что это функция только для zsh.

  • **/*(.)— все обычные файлы, напримерfind -type f
  • *(.)— все обычные файлы в текущем каталоге, напримерfind -maxdepth 1 -type f
  • **/*(.*)— исполняемые обычные файлы, напримерfind -type f -executable
  • **/*(U)— файлы, принадлежащие вызывающему пользователю, напримерfind -user $USER
  • **/*(.m-2)— обычные файлы, измененные менее 2 дней назад, напримерfind -type f -mtime -2
  • *(/^F)— пустые подкаталоги текущего каталога, напримерfind -mindepth 1 -maxdepth 1 -type d -empty

Вы также можете управлять сортировкой совпадений с помощью квалификатора glob. Например, echo *(.m-2om)печатает имена файлов, которые были изменены за последние 2 дня, от самых младших до самых старых.

Оболочки пропускают точечные файлы из совпадений с подстановочными знаками, если .в шаблоне нет начального. Это можно контролировать с помощью FIGNOREпеременной в ksh, GLOBIGNOREпеременной в bash или glob_dotsопции в zsh. В zsh вы можете использовать Dквалификатор glob для включения точечных файлов. В отличие от других оболочек, zsh никогда не будет включать совпадения .с ..подстановочными знаками.

Если вы хотите исключить некоторые каталоги из обхода, в zsh вы можете поставить косую черту под звездой Клини . Например, find -name .svn -prune -o -type fстановится(^.svn/)#*(.)

Команда findостается приоритетной, если совпадений очень много , поскольку она распечатывает файлы, как только они будут найдены, и выполняет команды по отдельности ( -exec … \;) или в пакетах ( -exec … +). Поскольку оболочка сортирует совпадения, она не может начать их отображение, пока не соберет их все, что может занять много времени. В последних версиях zsh есть Yквалификатор glob для остановки после определенного количества совпадений, например, **/*.txt(Y1)поиск .txtфайла в любом месте текущего каталога и остановка после его нахождения.

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

find -exec mycommand {} +
find -print0 | xargs -0 mycommand
printf %s\\0 **/* | xargs -0 mycommand
zargs -- **/* -- mycommand

Я не знаю ничего, что интегрируется findс locate.

смхайдрих

Отличный репортаж, большое спасибо! Некоторое время я думал о том, чтобы попробовать zsh, и теперь я убежден, что это хорошая идея. Для повседневного использования кажется, что вы можете быстрее добраться до сути того, что пытаетесь сделать, чем в bash.