шаблон `find -name`, который соответствует нескольким шаблонам

335

Я пытался получить список всех файлов Python и HTML в каталоге с помощью команды find Documents -name "*.{py,html}".

Затем появилась справочная страница:

Скобки в шаблоне ('{}') не считаются специальными (то есть find. -Name 'foo {1,2}' соответствует файлу с именем foo {1,2}, а не файлам foo1 и foo2.

Поскольку это часть конвейерной цепочки, я хотел бы иметь возможность указать, каким расширениям он соответствует во время выполнения (без жесткого кодирования). Если find просто не может этого сделать, однострочный perl (или аналогичный) будет в порядке.

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

Xiong Chiamiov
источник
Часто недооцениваемая и недоиспользуемая утилита также имеет место locate, хотя и с оговоркой, что внутренняя обновленная версия b может быть неактуальной. Но это быстро.
Майкл
Я голосую , чтобы закрыть этот вопрос не по теме , потому что она принадлежит на Unix и Linux
Dan Dăscălescu

Ответы:

481

Используйте -o, что означает «или»:

find Documents \( -name "*.py" -o -name "*.html" \)

Вам нужно построить эту командную строку программно, а это не так просто.

Вы используете bash (или Cygwin в Windows)? Если вы, вы должны быть в состоянии сделать это:

ls **/*.py **/*.html

который может быть проще построить программно.

RichieHindle
источник
3
Я использую zsh, который, как правило, поддерживает все bashisms, а также многое другое.
Сюн Чямов
12
Zsh поддерживает **рекурсивный поиск; Bash поддерживает его только в версиях 4.0 и выше и только с shopt -s globstar.
Гимн
2
Сколько у тебя может быть аргументов? У меня есть потенциально большой список файлов .gcda (данные о покрытии) для создания
Jasper Blues
40
Вам нужно заключить в две -nameскобки, если вы используете -exec. Напримерfind Documents \( -name "*.py" -o -name "*.html" \) -exec file {} \;
artbristol
2
Комментарий @artbristol очень важен, если, например, вы добавляете a -print0для обработки имен файлов с пробелами.
нимродм
63

Некоторые выпуски find, в основном в системах Linux, возможно, в других также поддерживают опции -regex и -regextype, которые находят файлы с именами, соответствующими регулярному выражению.

например

find . -regextype posix-egrep -regex ".*\.(py|html)$" 

следует сделать трюк в приведенном выше примере. Однако это не стандартная функция поиска POSIX и зависит от реализации.

интелект
источник
1
интересный, но более
сложный,
12
Проще: find . -regex ".*\.\(py\|html\)$"это работает, потому что по умолчанию находят регулярные выражения в стиле Emacs, которые немного отличаются, поэтому вам не нужно указывать тип регулярного выражения.
Робру
2
Если у вас много выражений, -regextype posix-egrepэто удобно (в противном случае вам нужно избегать большого количества символов). Это команда find, которую я использовал для dist-hook при создании zip-дистрибутива Windows (находит изменяемые файлы, а в файле изменяет их на dos-eol): find -regextype posix-egrep -regex ".*(\.([chyl]|def|cpy|cob|conf|cfg)|(README|ChangeLog|AUTHORS|ABOUT-NLS|NEWS|THANKS|TODO|COPYING.*))$" -exec sed -i -e 's/\r*$/\r/' {} \;
Simon Sobisch
32

Вы можете программно добавить больше -nameпредложений, разделенных -or:

find Documents \( -name "*.py" -or -name "*.html" \)

Или вместо этого перейдите к простому циклу:

for F in Documents/*.{py,html}; do ...something with each '$F'... ; done
Stephan202
источник
@ user2284570: тогда либо нет *.pyфайлов, либо у вас странная версия find. Команда, перечисленная выше, работает просто отлично.
Stephan202
Нет, я использую -iname. Он возвращает *.pyфайлы, только если записывает его в последней позиции ( iname *.htmlкак и первое выражение) . Я использую команду на Debian.
user2284570
Вы используете цитаты? Это очень важно
Stephan202
1
Это-или -о?
Стефан
1
@StephaneEybert: либо все в порядке, но только последний является POSIX-совместимым (согласно man-странице).
Stephan202
16

Это найдет все .c или .cpp файлы в Linux

$ find . -name "*.c" -o -name "*.cpp"

Вам не нужны экранированные скобки, если вы не используете дополнительные моды. Здесь со страницы руководства они говорят, что если шаблон соответствует, распечатайте его. Возможно, они пытаются контролировать печать. В этом случае -print действует как условный и становится условным «И». Это предотвратит печать любых файлов .c.

$ find .  -name "*.c" -o -name "*.cpp"  -print

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

$ find . \( -name "*.c" -o -name "*.cpp" \) -print

Последний пример для всех исходных файлов c / c ++

$ find . \( -name "*.c" -o -name "*.cpp"  -o -name "*.h" -o -name "*.hpp" \) -print
netskink
источник
11

У меня была похожая потребность. Это сработало для меня:

find ../../ \( -iname 'tmp' -o -iname 'vendor' \) -prune -o \( -iname '*.*rb' -o -iname '*.rjs' \) -print
bkidd
источник
3
Отлично. Но я нахожу немного странным, что это не работает без()
pedrofurla
Я хотел найти файлы, которые соответствовали * .c * .cpp или * .cc. Только с двумя именами-шаблонами мне не нужны были имена, но с тремя именами-шаблонами, соединенными с двумя -о-шаблонами, find -name "*.cpp" -o -name "*.c" -o -name "*.cc" -print0мне пришлось использовать пару символов, чтобы группа вторая или оператор. find -name "*.cpp" -o \( -name "*.c" -o -name "*.cc" \) -print0Может быть так, что -print0, который всегда "true", повлиял на логику.
Кардифф космический человек
5

Мой по умолчанию был:

find -type f | egrep -i "*.java|*.css|*.cs|*.sql"

Как и менее интенсивные процессы findисполнения Бренданом Лонгом и Стефаном202 и др .:

find Documents \( -name "*.py" -or -name "*.html" \)

Pase
источник
3
это не правильное использование egrepрегулярных выражений, скорее, у вас есть оболочка, где следует использовать регулярное выражение. (Кроме того, типичное findиспользование:, find {directory} [options...] [action]где, в зависимости от impl, directoryможет по умолчанию .и по actionумолчанию -print, но я буду в явном виде.) Вместо этого, используйте что-то вроде: find . -type f -print | egrep -i '\.java$|\.css$|\.cs$|\.sql$' Но также, как очень быстрая альтернатива find, можно также попробуйте locateаналогичным образом (хотя и не обязательно в актуальном состоянии, так как он запрашивает внутреннюю базу данных для списка файлов)
Майкл
2
#! /bin/bash
filetypes="*.py *.xml"
for type in $filetypes
do
find Documents -name "$type"
done

просто но работает :)

mnrl
источник
1

Мне нужно было удалить все файлы в дочерних каталогах, за исключением некоторых файлов. У меня сработало следующее (указаны три модели):

find . -depth -type f -not -name *.itp -and -not -name *ane.gro -and -not -name *.top -exec rm '{}' +
саман
источник
1

Брекеты в шаблоне \(\)требуются для шаблона имени сor

find Documents -type f \( -name "*.py" -or -name "*.html" \)

Пока для шаблона имени с andоператором это не требуется

find Documents -type f ! -name "*.py" -and ! -name "*.html" 
Chetabahana
источник
0

Это работает на AIX Korn Shell.

find *.cbl *.dms -prune -type f -mtime -1

Это ищет *.cblили *.dmsкоторые 1 день, только в текущем каталоге, пропуская подкаталоги.

Абдул М Гилл
источник
0
find MyDir -iname "*.[j][p][g]"
+
find MyDir -iname "*.[b][m][p]"
=
find MyDir -iname "*.[jb][pm][gp]"
user7531934
источник
2
Обратите внимание, что последний будет соответствовать foo.jmg, но ни один из двух лучших не будет.
медь. Что
0

Что о

ls {*.py,*.html}

В нем перечислены все файлы, заканчивающиеся на .py или .html в их именах файлов.

Dr_Hope
источник