Вот относительно простое решение, которое запускает find
только один раз, сохраняет свои выходные данные во временном файле, а затем разбивает их на части и объединяет результаты для двух расширений.
tmp=$(mktemp)
find . -name '*.ext1' -o -name '*.ext2' | sort >"$tmp"
comm -12 <(<tmp sed -n 's!/[^/]*\.ext1$!!p' | sort) \
<(<tmp sed -n 's!/[^/]*\.ext2$!!p' | sort)
rm "$tmp"
Другой метод - запустить find
для итерации по каталогам и использовать вспомогательную программу для проверки соответствия шаблона. Обратите внимание, что проверка существования в этом случае работает, но вам нужно нечто более сложное, если ваш шаблон поиска не соответствует самому себе и является возможным именем файла.
find . -type d -exec sh -c '{ set "$0"/*.ext1; [ -e "$1" ]; } &&
{ set "$0"/*.ext2; [ -e "$1" ]; }' {} \;
Вот решение zsh, которое работает как эта последняя команда:
echo **/*(/e\''set -- $REPLY/*.ext1(N[1]) $REPLY/*.ext2(N[1]); ((#==2))'\')
Вот еще одно решение zsh, которое ищет *.ext1
и выбирает только каталоги, которые также имеют *.ext2
:
echo ./**/*.ext1(e\''REPLY=${REPLY:h}; set -- $REPLY/*.ext2(N); ((#))'\')
Вот частичное решение Perl; из-за превратностей глобализации Perl, он не будет работать, если имена каталогов содержат пробелы (есть способы исправить это, но я не могу найти тот, который удаленно элегантен).
perl -l -MFile::Find -e \
'find {no_chdir => 1,
wanted => sub {<$_/*.ext1> and <$_/*.ext2> and print}}, "."'