Я хотел бы найти все каталоги, которые содержат как Makefile и файл, соответствующий *.tex . Команда find или locate легко находит одно или другое. Но как эти результаты можно объединить или пересечь, чтобы получить только нужные каталоги?

Полезный ответ обобщает другие имена файлов. Более того, он может объединять более двух таких запросов.

(Я не вижу, как применять логические операторы find , например, "and" expr1 -a expr2 . То же самое для locate -A . Может быть, два поиска, вырезать имена файлов и сохранить пути, sort -u , в comm -12 <(cmd1) <(cmd2)?)

2 ответа2

4

Просто используйте -a для условий «И»:

find . -type d -exec test -f {}/Makefile \; -a -exec bash -c 'compgen -G '{}'/*.tex >/dev/null;exit $?' \; -print

В замедленном режиме:

  • -exec test -f {}/Makefile \; проверяет, существует ли Makefile в каталоге
  • -exec bash -c 'compgen -G '{}'/*.tex >/dev/null;exit $?' проверяет, есть ли в каталоге файлы *.tex
  • вся строка проверяет истину, только если оба теста верны
  • в этом случае выведите имя каталога

Побежал по:

./no1
./no1/yes3
./no1/yes3/foo.tex
./no1/yes3/Makefile
./no1/no3
./no1/no
./no1/Makefile
./q
./no2
./no2/foo.tex
./yes1
./yes1/foo.tex
./yes1/Makefile
./yes2
./yes2/foo.tex
./yes2/Makefile

дает:

./no1/yes3
./yes1
./yes2
1

find не может выполнять «подзапросы» для печати каталогов, которые содержат некоторые файлы, так что comm - это действительно путь:

comm -12 <(find . -name Makefile -exec dirname {} \; | sort ) <(find . -name '*.tex' -exec dirname {} \; | sort)

Вы также можете зацикливать каталоги (рекурсивно с globstar), что может быть быстрее (источник compgen):

for directory in */
do
    if [ -e "${directory}/Makefile" ] && compgen -G "${directory}/"*.tex > /dev/null
    then
        printf '%s\n' "${directory}"
    fi
done

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .