Я хотел бы найти файлы PDF, чье имя (исключая расширение) больше трех.
$ find ~ -iregex ".{3,}/.pdf"
ничего не возвращает, но
$ find ~ -iregex ".+/.pdf"
работает.
Как я могу включить {3,}вариант?
Я хотел бы найти файлы PDF, чье имя (исключая расширение) больше трех.
$ find ~ -iregex ".{3,}/.pdf"
ничего не возвращает, но
$ find ~ -iregex ".+/.pdf"
работает.
Как я могу включить {3,}вариант?
Ответы:
Предполагая, что вы используете GNU find(которым вы, вероятно, являетесь, поскольку он -iregexявляется расширением GNU для POSIXfind ), -regexи по -iregexумолчанию используются регулярные выражения Emacs, которые не распознаются {3,}. Вы должны указать другой тип регулярных выражений, используя -regextypeопцию; Кроме того, вам нужно настроить регулярное выражение так, чтобы оно совпадало с полным путем:
find ~ -regextype posix-extended -iregex '.*/[^/]{3,}.pdf'
Вы также должны избегать, .чтобы он соответствовал «.» а не любой персонаж:
find ~ -regextype posix-extended -iregex '.*/[^/]{3,}\.pdf'
Регулярное выражение может быть упрощено, так как мы заботимся только о трех символах, отличных от «/»:
find ~ -regextype posix-extended -iregex '.*[^/]{3}\.pdf'
Для полноты, с FreeBSD или NetBSD find(другая реализация, которая поддерживает -iregex, а не ваша, хотя .+и не будет работать без нее -E), вы должны написать:
find ~ -iregex '.*[^/]\{3\}\.pdf'
или:
find -E ~ -iregex '.*[^/]{3}\.pdf'
Без -E, это основное регулярное выражение (как в grep) и с -E расширенным регулярным выражением (как в grep -E).
С ast-open's find:
find ~ -iregex '.*[^/]{3}\.pdf'
(это расширенные регулярные выражения из коробки).
Здесь проще со стандартными подстановочными знаками:
find ~ -name '*???.[pP][dD][fF]'
Или с некоторыми findреализациями (те, которые поддерживают, -regexтакже поддерживают -iname):
find ~ -iname '*???.pdf'
Для произвольного числа символов вместо 3этого, вы можете предпочесть вернуться туда, -iregexгде доступно (см . Ответ @Stephen Kitt ), или вы можете использовать zshили ksh93globs:
zsh:
set -o extendedglob # best in ~/.zshrc
printf '%s\n' ~/**/?(#c3,).(#i)pdf(D)
( (D)чтобы рассматривать скрытые файлы и файлы в скрытых папках, как с find)
(#cx,y)является zshподстановочным эквивалентом регулярного выражения{x,y}(#i) без учета регистра?стандартный подстановочный знак для любого отдельного символа (например, регулярное выражение .)**/: любой уровень подкаталогов (включая 0)ksh93:
FIGNORE='@(.|..)' # to consider hidden files
set -o globstar
printf '%s\n' **/{3,}(?).~(i:pdf)
@(x|y): расширенный шаблонный символ ksh, похожий на регулярное выражение (x|y).FIGNORE: специальная переменная, которая контролирует, какие файлы игнорируются глобусами. Когда установлено, обычное игнорирование скрытых файлов не будет сделано, но мы все еще хотим , чтобы игнорировать .и ..запись каталога , где присутствуют.{x,y}(z)является ksh93эквивалентом регулярного выражения z{x,y}.~(i:...): регистронезависимое соответствие.Глобусы имеют некоторые дополнительные преимущества по сравнению с findтем, что вы получаете отсортированный список (вы можете отключить эту сортировку zshс помощью oNквалификатора глобуса или использовать другие критерии сортировки), а также работать, когда имена файлов содержат последовательность байтов, которые не образуют допустимых символов (для Например, в локали, использующей кодировку UTF-8, findподход не будет сообщать о a $'St\xE9phane Chazelas - CV.pdf, \xE9поскольку не являющийся символом не соответствует регулярному выражению, .подстановочному знаку ?или *GNU find).
shopt -s dotglob globstar; printf '%s\n' ~/**/*???.[pP][dD][fF]
Вы этого не сделаете, если не спросите. Конечно, я педантичен, но вы не спрашивали о файлах с .pdfих именами . Тот факт, что файл содержит символы .pdfв имени файла , не делает его файлом PDF .
На самом деле, давайте будем педантичны во всем этом: если последние четыре символа имени файла .pdf, то в его имени всегда будет более трех символов .
Таким образом, делая это неправильно , вы можете сказать:
$ find . -type f -name "*???.pdf"
./Documents/McLaren 720s Coupe:Order Summary.pdf
./Documents/Setup_MagicISO.exe.pdf
Видишь этот второй? Это на самом деле исполняемый файл. (Я знаю, я изменил имя.) И мне также не хватает PDF, который я мог поклясться, был в каталоге документов ...
$ ls Documents
McLaren 720s Coupe:Order Summary.pdf
Pioneer Premier DEH-P490IB CD Install Manual.PDF
Setup_MagicISO.exe.pdf
Таким образом, используя его, -inameмы могли бы найти его, но он все еще включает этот файл, не являющийся файлом PDF.
В этом случае мы действительно хотим проверить магическое число файла с помощью fileкоманды. Одна опция выводит тип MIME , который проще анализировать. findЗапрос становится простым -name "???*".
$ find . -type f -name "???*" -print0|xargs -0 file --mime
./.bash_history: text/plain; charset=us-ascii
./.bash_logout: text/plain; charset=us-ascii
./.bashrc: text/plain; charset=us-ascii
./.profile: text/plain; charset=us-ascii
./Documents/McLaren 720s Coupe:Order Summary.pdf: application/pdf; charset=binary
./Documents/Pioneer Premier DEH-P490IB CD Install Manual.PDF: application/pdf; charset=binary
./Documents/Setup_MagicISO.exe.pdf: application/x-dosexec; charset=binary
./Downloads/Setup_MagicISO.exe: application/x-dosexec; charset=binary
./Downloads/WindowsUpdate.diagcab: application/vnd.ms-cab-compressed; charset=binary
Давайте используем разделитель двоеточий и ищем MIME-тип application/pdf, затем обнуляем эту часть и выводим результат. Обратите внимание, у одного из моих файлов есть двоеточие в имени; поэтому я не могу просто спросить awk ($2==":"){print $1}.
$ find . -type f -name "???*" -print0|xargs -0 file --mime|awk -F: '($NF~"application/pdf"){OFS=":";$NF="";print}'|sed s/:$//
./Documents/McLaren 720s Coupe:Order Summary.pdf
./Documents/Pioneer Premier DEH-P490IB CD Install Manual.PDF
Теперь давайте закончим, придумав включить файлы PDF с именами aи abc:
$ mkdir Documents/other
$ cp -a Documents/McLaren\ 720s\ Coupe\:Order\ Summary.pdf Documents/other/a
$ cp -a Documents/Pioneer\ Premier\ DEH-P490IB\ CD\ Install\ Manual.PDF Documents/other/abc
$ find . -type f -name "???*" -print0|xargs -0 file --mime|awk -F: '($NF~"application/pdf"){OFS=":";$NF="";print}'|sed s/:$//
./Documents/McLaren 720s Coupe:Order Summary.pdf
./Documents/Pioneer Premier DEH-P490IB CD Install Manual.PDF
./Documents/other/abc
Это все. Я знаю, что мне, вероятно, не понравится, что я ужасно педантичен, но в моей работе с тысячами томов NFS для охоты и всеми видами плохо названных файлов я бы хотел, чтобы больше людей были педантичными.
Отредактировано, чтобы добавить: в реальном мире, я мог бы хотеть использовать updatedbдля создания индекса файла с возможностью поиска, locateвместо того, findчтобы читать этот индекс, а parallelне для того, xargsчтобы продолжить работу. Это несколько выходит за рамки этого вопроса, хотя. Я написал это с невозмутимым лицом тоже. Почему меня это так волнует? Я мог бы искать кино и аудио файлы; или определенные типы фотографий; или двоичные исполняемые файлы в каталоге данных проекта.
.pdf, тогда ваша педантичность будет высоко оценена. Но это относительно необычная ситуация (несмотря на вашу работу), и у нас нет никаких оснований полагать, что спрашивающему действительно приходится иметь дело с этим, поэтому я считаю, что мысль, которую вы выдвигаете, хотя и действительна, отчасти отвлекает - и я думаю, что силовая формулировка, которую вы сформулировали, толкает ответ в область «(вероятно) бесполезной». (Только мое мнение, конечно.)