Рекурсивный шар?

80

Я хотел бы написать что-то вроде этого:

$ ls **.py

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

Даже если есть файлы .py, которые нужно найти, оболочка (bash) выдает следующее:

ls: cannot access **.py: No such file or directory

Любой способ сделать то, что я хочу?

РЕДАКТИРОВАТЬ: Я хотел бы указать, что я не заинтересован в конкретном случае ls, но вопрос о синтаксисе glob.

Paolo
источник

Ответы:

98

Для создания рекурсивных шаров в bash вам нужна globstarфункция из bash версии 4 или выше.

Из справочной страницы bash:

globstar
    If set, the pattern ** used in a pathname expansion context will
    match all files and zero or more directories and subdirectories.
    If the pattern is followed by a /, only directories and
    subdirectories match.

Для вашего примера шаблона:

shopt -s globstar
ls **/*.py
jordanm
источник
2
Я бы порекомендовал также включитьnullglob
Гленн Джекман
6
@glennjackman Но перед включением nullglobя настоятельно рекомендую прочитать следующие предупреждения .
Серж Строобандт
2
^ Предупреждения перенесены сюда .
usandfriends
1
С bash 3.2 wc -l {**,.}/*.pyработает просто отлично
Рафаэль
@Raphael Я дважды проверил примечания к выпуску, и он определенно говорит, что он был представлен в 4.0. Возможно, в вашем дистрибутиве есть патч для него? IIRC RHEL 5 поддерживал некоторые функции. Также следует отметить, что прошло 9 лет с момента выхода bash 4 ...
Иордания,
10
find . -name '*.py'

** не делает ничего, кроме одного *, оба работают в текущем каталоге

doneal24
источник
Интересно. Тем не менее, я больше сосредоточен на синтаксисе glob сам по себе, потому что я должен использовать его в файле конфигурации (директива include). Мне не нужен список файлов.
Паоло
2
@ Дуг О'Нил, это больше не правда. bash теперь скопировал эту функцию zsh (хотя он принял синтаксис, близкий к синтаксису ksh93 и, подобно ksh, пока не поддерживает глобальные классификаторы zsh, что ограничивает его полезность)
Стефан Шазелас
Есть много вещей, с которыми вы можете делать, findесли у вас нет bash 4. Примеры: yourcommand `find . -name '*.py'`(обратите внимание на обратные ссылки); find . -name '*.py' -exec yourcommand {} \;,
Марс
5

Начиная с Bash 4 (также включая zsh) была добавлена ​​новая опция globbing ( globstar), которая обрабатывает шаблон по- **разному, когда он установлен.

Он сопоставляется с шаблоном подстановки и возвращает имена файлов и каталогов, которые затем соответствуют, заменяя шаблон подстановки в команде соответствующими элементами.

Обычно при использовании **он работает аналогично *, но рекурсивно рекурсивно обращается ко всем каталогам (например, цикл).

Чтобы увидеть, включен ли он, проверьте его с помощью shopt globstar(в сценариях используйте shopt -q globstar).

Этот пример **.pyбудет работать только для текущего каталога, так как он не возвращает список каталогов, которые могут быть рекурсивными, поэтому вам нужно использовать несколько подстановочных знаков уровня каталога **/*.py, чтобы он мог идти глубже.

Пожалуйста, найдите на SO несколько синтаксических тестов, которые я сделал для рекурсивного поиска всех файлов.

kenorb
источник