Шаблон `find -name`, який відповідає декільком шаблонам


335

Я намагався отримати список усіх файлів python та html у каталозі з командою find Documents -name "*.{py,html}".

Потім з'явилася сторінка людини:

Дужки в шаблоні ('{}') не вважаються спеціальними (тобто знайдіть. -Name 'foo {1,2}' відповідає файлу з ім'ям foo {1,2}, а не файлам foo1 та foo2.

Оскільки це частина ланцюга трубопроводів, я хотів би мати можливість вказати, яким розширенням він відповідає під час виконання (без жорсткого кодування). Якщо знайти просто не в змозі цього зробити, перламутровий однолінійний (або подібний) буде добре.

Редагувати: Відповідь, яку я врешті-решт придумав, включає всілякі лайно, а також трохи довгі, тому я розмістив її як відповідь на оригінальний свербіж, який я намагався подряпати. Ви можете зламати це, якщо у вас є кращі рішення.



Також часто не помічається і недостатньо використовувана утиліта locate, хоч із застереженням, що внутрішній оновленийb може не бути оновленим. Але це швидко.
Майкл

Я голосую, щоб закрити це питання поза темою, оскільки воно належить до Unix & Linux
Dan Dascalescu,

Відповіді:


481

Використовувати -o, що означає "або":

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

Вам потрібно було б побудувати цей командний рядок програмно, що не так просто.

Ви використовуєте bash (або Cygwin у Windows)? Якщо ви є, ви повинні зробити це:

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

що може бути простіше побудувати програмно.


3
Я використовую zsh, який, як правило, підтримує всі башизми, плюс більше.
Xiong Chiamiov

12
Zsh підтримує **рекурсивний пошук; Bash підтримує його лише у версіях 4.0 і новіших версій і лише з shopt -s globstar.
ефемієнт

2
Скільки -о арг у вас може бути? У мене є потенційно великий список .gcda (даних про покриття), які потрібно створити
Jasper Blues

40
-nameЯкщо ви користуєтесь, вам потрібно оточити два s за допомогою дужок -exec. Напр.find Documents \( -name "*.py" -o -name "*.html" \) -exec file {} \;
артбрістоль

2
Коментар @artbristol дуже актуальний, якщо, наприклад, ви додаєте, -print0щоб обробляти імена файлів з пробілами.
nimrodm

63

Деякі видання знаходять, в основному, в системах Linux, можливо, в інших також підтримуються параметри -regex і -regextype, де знаходять файли з іменами, що відповідають регексу.

наприклад

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

слід зробити фокус у наведеному вище прикладі. Однак це не є стандартною функцією пошуку POSIX і залежить від реалізації.


1
заперечення, але складніші за інші відповіді
m1k3y3

12
Простіше: find . -regex ".*\.\(py\|html\)$"це працює, тому що знаходять за замовчуванням регулярні вирази у стилі Emacs, які дещо відрізняються, тому вам не потрібно вказувати регекст.
robru

2
Якщо у вас є багато виразів, -regextype posix-egrepце зручно (інакше вам потрібно буде уникати безлічі символів). Це команда find, яку я використовував для створення диска-гачка для створення 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/' {} \;
Саймон Собіш

32

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

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

Або замість цього перейдіть до простого циклу:

for F in Documents/*.{py,html}; do ...something with each '$F'... ; done

@ user2284570: тоді або *.pyфайлів немає, або у вас є якась дивна версія find. Перерахована вище команда працює чудово.
Stephan202

Ні, я використовую -iname. Він повертає *.pyфайли, лише якщо записати їх в останньому положенні (так iname *.htmlце перший вираз) . Я використовую команду на Debian.
користувач2284570

Ви використовуєте цитати? Це дуже важливо.
Stephan202

1
Це -орі або -о?
Стефан

1
@StephaneEybert: або це добре, але лише остання сумісна з POSIX (відповідно до сторінки man).
Стефан202

16

Це знайде всі .c або .cpp файли на Linux

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

Вам не потрібні круглі дужки, якщо ви не робите деякі додаткові моди. Тут зі сторінки чоловіка вони говорять, якщо візерунок збігається, роздруковуйте його. Можливо, вони намагаються контролювати друк. У цьому випадку -принт діє як умовний і стає умовним "AND'd". Це запобіжить друку будь-яких файлів .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

11

У мене була схожа потреба. Це працювало для мене:

find ../../ \( -iname 'tmp' -o -iname 'vendor' \) -prune -o \( -iname '*.*rb' -o -iname '*.rjs' \) -print

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, який завжди є "правдою".
людина з космосом Кардіфф

5

Моїм замовчуванням було:

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

Як і менш умисне findвиконання Брендана Лонга та Стефана202 та ін .:

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


3
це не правильно використання egrepregexp, скоріше, ви маєте глобул оболонки, де слід використовувати регулярний вираз. (Також типовим findвикористанням є:, find {directory} [options...] [action]де, залежно від impl, directoryможе бути за замовчуванням .та actionза замовчуванням -print, але я буду явним.) Отже, замість цього використовуйте щось на кшталт: find . -type f -print | egrep -i '\.java$|\.css$|\.cs$|\.sql$' Але також, як справді швидку альтернативу find, можна також спробуйте locateподібним чином (хоча це не обов'язково в актуальному стані, оскільки він запитує внутрішній db для списку файлів)
michael

2
#! /bin/bash
filetypes="*.py *.xml"
for type in $filetypes
do
find Documents -name "$type"
done

просто, але працює :)


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" 

0

Це працює на оболонці кукурудзи AIX.

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]"

2
Зауважте, що останній буде відповідати foo.jmg, але жоден з двох найкращих не буде.
мідь.характер

0

А як на рахунок

ls {*.py,*.html}

У ньому перераховані всі файли, що закінчуються .py або .html у своїх іменах

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.