Найти файлы, имеющие то же имя, что и каталог

Найти файлы, имеющие то же имя, что и каталог

У меня следующая проблема:

В каталоге Example1три файла: Example1, Thingsи Pictures.

В каталоге Example2три файла: Example2, Example3и Pictures.

Мне нужен список, показывающий только те файлы, которые соответствуют имени каталога, это: Example1и Example2. Я пробовал использовать diff, find, locate и ls..., но ничего не добился.

решение1

Вы можете легко сопоставить имена файлов, которые имеют то же имя, что и содержащий каталог, с регулярным выражением, используя обратную ссылку. Это имена файлов в форме, what/ever/something/somethingгде две somethingчасти идентичны и не содержат слеша. В синтаксисе регулярных выражений BRE [^/]*соответствует любой строке, которая не содержит слеша, \(/[^/]*\)соответствует слешу, за которым следует любое количество символов, не являющихся слешем, и делает все это группой, и \1соответствует тому же тексту, который соответствует первой группе, поэтому \(/[^/]*\)\1соответствует двум сегментам пути с одинаковым именем. Добавьте .*в начало, чтобы соответствовать предыдущим компонентам каталога.

С помощью GNU find, FreeBSD find, macOS find или любой другой, findкоторая поддерживает -regex:

find . -regex '.*\(/[^/]*\)\1'

решение2

Поскольку каталогов, как правило, меньше, чем файлов, давайте найдем все каталоги, а затем проверим, содержат ли они требуемое имя файла.

find . -type d -exec sh -c '
    for dirpath do
        filepath="$dirpath/${dirpath##*/}"
        [ -f "$filepath" ] && printf "%s\n" "$filepath"
    done' sh {} +

Это позволит вывести пути ко всем обычным файлам (и символическим ссылкам на обычные файлы), расположенным в каталоге с тем же именем, что и у файла.

Тест выполняется в коротком встроенном sh -cскрипте, который получает несколько путей к каталогам в качестве аргументов. Он перебирает каждый путь к каталогу и создает путь к файлу с именем, которое мы ищем. ${dirpath##*/}В коде можно заменить на $(basename "$dirpath").

Для данного примера структуры каталогов это выведет

./Example1/Example1
./Example2/Example2

Чтобы просто проверитьлюбое имя, а не просто обычные файлы, измените -fтест на -eтест.

решение3

Использовать find -exec:

find . -type f \
  -exec sh -c '[ "$(basename "$1")" = "$(basename "$(dirname "$1")")" ]' find-sh {} \; \
  -print

Выполнение -printбудет выполнено только в том случае, если результат внутреннего выражения [ ... ]будет -exec sh -c '...'истинным.

Выход:

./Example1/Example1
./Example2/Example2

Связанный контент