У меня есть дерево каталогов, в котором я хочу выполнить рекурсивный поиск всех файлов определенного типа (например, всех .jpg
файлов ), но я хочу вывести список этих файлов только в том случае, если они находятся в самом низу дерева каталогов.
Например, если мое дерево выглядит так:
home
root
f1 f2 f3
f11 f22 f33
f111 f222 f333
и все папки содержат .jpg
', я хочу перечислить только .jpg
' в f111
/ f222
/ f333
и т. д. и игнорировать те, что находятся в папках выше.
Я знаю, что могу использовать команду find (например, find . -name "*.jpg"
), чтобы получить список всех .jpg
папок во всем дереве, но я не уверен, как ограничить его только самыми нижними папками, не прибегая к grep
фильтрации результатов по символам 111
/ 222
/ 333
, что на самом деле невыполнимо, поскольку у меня сотни папок, и я не знаю, как могут называться папки последнего уровня для каждой из них по отдельности.
решение1
Это можно сделать в два этапа:
find . -type d -links 2 -print0 | xargs -0 -I{} find {} -name \*.jpg
Первая команда выводит список всех каталогов без подкаталогов (поскольку каждый подкаталог добавляет единицу к количеству ссылок, а пустой каталог добавляет две). Вторая вызывает find
вручную каждый из этих результатов.
решение2
Эквивалент POSIXРешение @TomHunt.
find . -type d -links 2 -exec sh -c '
find "$@" -type f -name "*.jpg"' sh {} +
Полагается -links 2
на свойство некоторых файловых систем, что количество ссылок каталогов (изначально 2 для записи в их родителе и записи .
в них самих) увеличивается на единицу для каждого подкаталога (из-за ..
записи в них). Некоторые современные файловые системы, такие как btrfs
или nilfs
, чьи структуры радикально отличаются, не имеют такого свойства.
С помощью zsh
можно сделать что-то вроде:
has_subdirs() {
local l
l=($REPLY/*(/DNoN[1]))
(($#l))
}
dirs_without_subdirs=(**/*(DN^+has_subdirs))
jpgs=($^dirs_without_subdirs/*.jpg(ND.))
(($#jpgs)) && printf '%s\n' $jpgs