Hy, я получил большое дерево каталогов. Я хочу узнать все каталоги, которые содержат файл, которые называют концы с ".ext1" и файлом, которые называют концы с ".ext2".
Как это возможно? Я думал об использовании два, находит, один для ".ext1" и один для ".ext2", но затем я должен найти пересечение, как это может быть сделано?
Спасибо!
Вот относительно простое решение, которое работает 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; из-за превратностей globbing Perl, это не будет работать, если имена каталогов будут содержать пробелы (существуют способы зафиксировать это, но я не могу найти тот, который это удаленно изящно).
perl -l -MFile::Find -e \
'find {no_chdir => 1,
wanted => sub {<$_/*.ext1> and <$_/*.ext2> and print}}, "."'
Если Вы знаете точное название каждого файла:
find start_dir -type d -exec test -e {}/file.ext1 -a -e {}/file.ext2 \; -print
Исключительно ужасный взлом будет работать, если все, что Вы знаете, будет расширениями:
find start_dir -type d -execdir bash -c 'shopt -s nullglob; eval '\''test -n "$(echo '{}'/*.ext1)" -a -n "$(echo '{}'/*.ext2)"'\''' \; -print
Это могло также быть довольно медленно, если у Вас есть много каталогов для поиска.