Bash: Найдите папку, содержащую два файла

Hy, я получил большое дерево каталогов. Я хочу узнать все каталоги, которые содержат файл, которые называют концы с ".ext1" и файлом, которые называют концы с ".ext2".

Как это возможно? Я думал об использовании два, находит, один для ".ext1" и один для ".ext2", но затем я должен найти пересечение, как это может быть сделано?

Спасибо!

3
задан 15.09.2010, 15:29

4 ответа

Вот относительно простое решение, которое работает 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}}, "."'
5
ответ дан 07.12.2019, 23:17

Если Вы знаете точное название каждого файла:

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

Это могло также быть довольно медленно, если у Вас есть много каталогов для поиска.

2
ответ дан 07.12.2019, 23:17

Если выполнено от главы дерева каталогов, это, кажется, работает

find $(find . -name "*.ext1" -printf %h\\n) -name "*.ext2" -printf %h\\n
1
ответ дан 07.12.2019, 23:17

Должно быть лучшее решение, но:

find -type d | while read i ; do [ `ls "$i" -1 | grep -oe '.ext1$\|.ext2$' | sort -u | wc -l` = 2 ] && echo $i ; done
0
ответ дан 07.12.2019, 23:17

Теги

Похожие вопросы