Вот решение, основанное только на POSIX find и POSIX sh. Перечислите все каталоги, затем отфильтруйте те, которые содержат только запись с именем .DS_Store
.
find -type d -exec sh -c '
cd "$0" &&
for x in *.[!.]*..?*; do
if [ "$x" = ".DS_Store" ]; then continue; fi;
if [ -e "$x" ] || [ -L "$x" ]; then exit 1; fi;
done' {} \; -print
find
для рекурсивного перечисления всех каталогов. sh
для запуска кода оболочки. for
перебирает все файлы в каталоге. .DS_Store
. [ -e "$x" ] || [ -L "$x" ]
захватывает любой файл, включая битые символические ссылки; единственный способ, которым они не совпадают, - это если шаблон остался неизменным. exit 1
, если есть файл, отличный от .DS_Store
,и возвращает 0 в случае успеха в противном случае. -print
на -exec …
, если вы хотите сделать что-то другое, кроме печати имен. Вот решение в zsh. Измените echo
на любую команду, которую вы хотите запустить.
setopt extended_glob
echo **/*(/DNe\''a=($REPLY/^.DS_Store(DNY1)); ((!#a))'\')
**/*
рекурсивно перечисляет все файлы. /
, **/*(/)
рекурсивно перечисляет все каталоги. N
гарантирует, что вы получите пустой список, если нет совпадений (по умолчанию zsh сигнализирует об ошибке ). D
приводит к включению точечных файлов. e\''CODE'\'
запускает CODE
для каждого совпадающего имени файла и ограничивает совпадения теми, для которых CODE
успешно. CODE
может использовать переменную $REPLY
для ссылки на имя файла. ^.DS_Store
соответствует файлам, которые не называются .DS_Store
. .DS_Store
, равно нулю. Y1
ограничивает совпадения до одного (это всего лишь повышение эффективности ). Вот решение на Python (оно работает как на 2, так и на 3 ). Структура более четкая, несмотря на то, что она сжата в один -вкладыш.
python -c 'import os; print("\n".join([path for path, dirs, files in os.walk(".") if dirs == [] and files in ([], [".DS_Store"])]))'
os.walk
рекурсивно возвращает список каталогов по своему аргументу. Для каждого каталога создается тройка, содержащаяpath
(путь к каталогу ),dirs
(список подкаталогов )иfiles
(список файлов в каталоге, которые сами по себе не являются каталогами ). ]. [… for … in os.walk(…) if …]
фильтрует результат os.walk
. if
сохраняет элемент, только если он не имеет подкаталогов и файлов, отличных от .DS_Store
.