Я хочу найти все подпапки, которые содержат файл уценки с тем же именем (и расширением .md
).
Например: я хочу найти следующие подпапки:
Apple/Banana/Orange #Apple/Banana/Orange/Orange.md exists
Apple/Banana #Apple/Banana/Banana.md exists
Apple/Banana/Papaya #Apple/Banana/Papaya/Papaya.md exists
- Примечание. В каталоге могут быть другие файлы или подкаталоги.
Какие-либо предложения?
Решения проблемы могут быть проверены с использованием следующего кода:
#!/usr/bin/env bash
# - goal: "Test"
# - author: Nikhil Agarwal
# - date: Wednesday, August 07, 2019
# - status: P T' (P: Prototyping, T: Tested)
# - usage: ./Test.sh
# - include:
# 1.
# - refer:
# 1. [directory - Find only those folders that contain a File with the same name as the Folder - Unix & Linux Stack Exchange](/unix/534190/find-only-those-folders-that-contain-a-file-with-the-same-name-as-the-folder)
# - formatting:
# shellcheck disable=
#clear
main() {
TestData
ExpectedOutput
TestFunction "${1:?"Please enter a test number, as the first argument, to be executed!"}"
}
TestFunction() {
echo "Test Function"
echo "============="
"Test${1}"
echo ""
}
Test1() {
echo "Description: Thor"
find . -type f -regextype egrep -regex '.*/([^/]+)/\1\.md$' | sort
echo "Observation: ${Green:=}Pass, but shows filepath instead of directory path${Normal:=}"
}
Test2() {
echo "Description: Kusalananda1"
find . -type d -exec sh -c '
dirpath=$1
set -- "$dirpath"/*.md
[ -f "$dirpath/${dirpath##*/}.md" ] && [ "$#" -eq 1 ]' sh {} \; -print | sort
echo "Observation: ${Red:=}Fails as it ignores B.md${Normal:=}"
}
Test3() {
echo "Description: Kusalananda2"
find . -type d -exec sh -c '
for dirpath do
set -- "$dirpath"/*.md
if [ -f "$dirpath/${dirpath##*/}.md" ] && [ "$#" -eq 1 ]
then
printf "%s\n" "$dirpath"
fi
done' sh {} + | sort
echo "Observation: ${Red:=}Fails as it ignores B.md${Normal:=}"
}
Test4() {
echo "Description: steeldriver1"
find . -type d -exec sh -c '[ -f "$1/${1##*/}.md" ]' find-sh {} \; -print | sort
echo "Observation: ${Green:=}Pass${Normal:=}"
}
Test5() {
echo "Description: steeldriver2"
find . -type d -exec sh -c '
for d do
[ -f "$d/${d##*/}.md" ] && printf "%s\n" "$d"
done' find-sh {} + | sort
echo "Observation: ${Green:=}Pass${Normal:=}"
}
Test6() {
echo "Description: Stéphane Chazelas"
find . -name '*.md' -print0 \
| gawk -v RS='\0' -F/ -v OFS=/ '
{filename = $NF; NF--
if ($(NF)".md" == filename) include[$0]
else exclude[$0]
}
END {for (i in include) if (!(i in exclude)) print i}'
echo "Observation: ${Red:=}Fails as it ignores B.md${Normal:=}"
}
Test7() {
echo "Description: Zach"
#shellcheck disable=2044
for fd in $(find . -type d); do
dir=${fd##*/}
if [ -f "${fd}/${dir}.md" ]; then
ls "${fd}/${dir}.md"
fi
done
echo "Observation: ${Green:=}Pass but shows filepath instead of directory${Normal:=}"
}
ExpectedOutput() {
echo "Expected Output"
echo "==============="
cat << EOT
./GeneratedTest/A
./GeneratedTest/A/AA
./GeneratedTest/B
./GeneratedTest/C/CC1
./GeneratedTest/C/CC2
EOT
}
TestData() {
rm -rf GeneratedTest
mkdir -p GeneratedTest/A/AA
touch GeneratedTest/index.md
touch GeneratedTest/A/A.md
touch GeneratedTest/A/AA/AA.md
mkdir -p GeneratedTest/B
touch GeneratedTest/B/B.md
touch GeneratedTest/B/index.md
mkdir -p GeneratedTest/C/CC1
touch GeneratedTest/C/index.md
touch GeneratedTest/C/CC1/CC1.md
mkdir -p GeneratedTest/C/CC2
touch GeneratedTest/C/CC2/CC2.md
mkdir -p GeneratedTest/C/CC3
touch GeneratedTest/C/CC3/CC.md
mkdir -p GeneratedTest/C/CC4
}
main "$@"
foo/foo.md
иfoo/bar.md
должныfoo
быть включены или исключены?-printf
команду find, вы можете получить любую часть совпадения, какую захотите, см. Мое редактированиеОтветы:
Предполагая, что ваши файлы имеют разумное имя, то есть не нужно
-print0
и т. Д. Вы можете сделать это с помощью GNU:Вывод:
Если вам нужно только имя каталога, добавьте
-printf
аргумент:Вывод при запуске на ваших обновленных тестовых данных:
источник
find . -type f | egrep '.*/([^/]+)/\1\.md$'
print0
.%h
в printf используется для типа данных int, которые должны быть отформатированы. Ссылка: строка формата printf - Википедия . Не могли бы вы объяснить эту часть? Как%h
здесь используется?find
, см. Раздел 3.2.2.1 в руководстве для более подробной информации.В системе GNU вы можете сделать что-то вроде:
источник
zsh
Упомяните предыдущее решение (оно получило, я полагаю, два из голосов), и не стесняйтесь указывать на любые недостатки в нем, которые могли бы побудить вас удалить его.Вышеприведенные команды найдут все каталоги ниже текущего каталога (включая текущий каталог) и выполнят короткий сценарий оболочки для каждого из них.
Код оболочки будет проверять, существует ли файл уценки с тем же именем, что и каталог внутри каталога, и является ли это единственным
*.md
именем в этом каталоге. Если такой файл существует и если это единственное*.md
имя, встроенный сценарий оболочки завершается с нулевым статусом выхода. В противном случае он выходит с ненулевым состоянием выхода (ошибка сигнализации).set -- "$dirpath"/*.md
Бит будет устанавливать позиционные параметры списка путевых имен , соответствующих шаблону (соответствует любому имени с суффиксом.md
в каталоге). Затем мы можем использовать$#
позже, чтобы увидеть, сколько совпадений мы получили из этого.Если скрипт оболочки
-print
завершится успешно, будет напечатан путь к найденному каталогу.Немного более быстрая версия, которая использует меньше вызовов встроенного скрипта, но не позволяет вам делать больше с найденными путями внутри
find
себя (хотя встроенный скрипт может быть дополнительно расширен):Те же команды, но не обращая внимания на наличие других
.md
файлов в каталогах:Смотрите также:
источник
Или
или
Чтобы избежать запуска по одному
sh
на файл.Это
find-sh
произвольная строка, которая становится нулевым позиционным параметром оболочки$0
- создание чего-то запоминающегося может помочь с отладкой в случае, если оболочка обнаружит ошибки (другие могут предложить использовать обычныйsh
или даже_
в качестве параметра «пропустить» по умолчанию).источник
Вот мой. Я добавил еще несколько каталогов и файлов для проверки. Мне тоже было скучно, поэтому я добавил время последнего изменения и MD5. Может быть, вы ищете дубликаты.
источник
Это потребует немного логики.
Вы также можете адаптировать это, чтобы вписаться в один вкладыш, используя блоки кода.
РЕДАКТИРОВАТЬ: Баш трудно.
basedir
не команда,dirname
не делает то, что я думал, так что давайте перейдем к расширению параметров.источник
dirname
это команда, которую вы ищете, и назначения не могут иметь пробелы вокруг=
.