![Найти файлы, имеющие то же имя, что и каталог](https://rvso.com/image/170677/%D0%9D%D0%B0%D0%B9%D1%82%D0%B8%20%D1%84%D0%B0%D0%B9%D0%BB%D1%8B%2C%20%D0%B8%D0%BC%D0%B5%D1%8E%D1%89%D0%B8%D0%B5%20%D1%82%D0%BE%20%D0%B6%D0%B5%20%D0%B8%D0%BC%D1%8F%2C%20%D1%87%D1%82%D0%BE%20%D0%B8%20%D0%BA%D0%B0%D1%82%D0%B0%D0%BB%D0%BE%D0%B3.png)
У меня следующая проблема:
В каталоге 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