Ответ 1
Это будет работать в Bash 4:
ls -l {,**/}*.ext
Для работы globstar
с двумя звездочками необходимо установить параметр globstar
(по умолчанию: on):
shopt -s globstar
От man bash
:
globstar If set, the pattern ** used in a filename expansion con‐ text will match a files and zero or more directories and subdirectories. If the pattern is followed by a /, only directories and subdirectories match.
Теперь мне интересно, не было ли когда-то ошибки в обработке globstar, потому что теперь, используя просто ls **/*.ext
Ext, я получаю правильные результаты.
Несмотря на это, я посмотрел на анализ, который kenorb выполнил с использованием репозитория VLC, и обнаружил некоторые проблемы с этим анализом и в своем ответе, приведенном выше:
Сравнение с выводом команды find
недопустимо, поскольку при указании -type f
не -type f
другие типы файлов (в частности, каталоги), а перечисленные команды ls
скорее всего, так и есть. Кроме того, одна из перечисленных команд, ls -1 {,**/}*.*
- которая, кажется, основана на моей выше, выводит только имена, которые включают точку для тех файлов, которые находятся в подкаталогах. Вопрос ОП и мой ответ содержат точку, поскольку в данном случае ищутся файлы с определенным расширением.
Однако наиболее важно то, что существует особая проблема с использованием команды ls
с шаблоном globstar **
. Многие дубликаты возникают, поскольку Bash расширяет шаблон для всех имен файлов (и имен каталогов) в проверяемом дереве. После расширения команда ls
перечисляет каждого из них и их содержимое, если они являются каталогами.
Пример:
В нашем текущем каталоге находится подкаталог A
и его содержимое:
A
└── AB
└── ABC
├── ABC1
├── ABC2
└── ABCD
└── ABCD1
В этом дереве **
расширяется до "AA/AB A/AB/ABC A/AB/ABC/ABC1 A/AB/ABC/ABC2 A/AB/ABC/ABCD A/AB/ABC/ABCD/ABCD1" (7 записей). Если вы сделаете вывод echo **
что точный результат вы получите, и каждая запись будет представлена один раз. Однако, если вы выполните ls **
она выведет список каждой из этих записей. Таким образом, по существу, это ls A
затем ls A/AB
и т.д., Поэтому A/AB
отображается дважды. Кроме того, ls
собирается отделить каждый вывод подкаталога отдельно:
...
<blank line>
directory name:
content-item
content-item
Таким образом, использование wc -l
подсчитывает все те пустые строки и заголовки разделов имен каталогов, которые сбрасывают счет еще дальше.
Это еще одна причина, почему вы не должны анализировать ls
.
В результате этого дальнейшего анализа я рекомендую не использовать шаблон globstar ни при каких обстоятельствах, кроме как перебирать дерево файлов следующим образом:
for entry in **
do
something "$entry"
done
В качестве окончательного сравнения я использовал исходный репозиторий Bash, который мне пригодился, и сделал это:
shopt -s globstar dotglob
diff <(echo ** | tr ' ' '\n') <(find . | sed 's|\./||' | sort)
0a1
> .
Я использовал tr
чтобы заменить пробелы на новые строки, которые действительны только здесь, поскольку ни одно имя не содержит пробелов. Я использовал sed
чтобы удалить ведущие ./
из каждой строки вывода из find
. Я отсортировал вывод find
поскольку он обычно не сортируется, а расширение глобусов в Bash уже отсортировано. Как видите, единственным выходом из diff
был текущий каталог .
вывод по find
. Когда я сделал ls ** | wc -l
ls ** | wc -l
на выходе было почти вдвое больше строк.