Скажем, у меня есть следующее:
./
Dir1/
Sub1/
Sub1.jpg
Sub2/
Sub2.jpg
Sub2.png
Sub2.txt
Dir2/
Sub1/
Sub1.doc
Sub1.txt
Sub2/
Sub2.jpg
Sub2.png
SomeTxt.txt
Dir3/
Dir3.txt
Dir4/
Sub1/
Dir4.txt
Some.txt
Используя удар (bashrc в моем случае), как я могу получить переменную, которая содержит все каталоги, содержащие текстовый файл (.txt) с тем же именем как содержание каталога? Таким образом от примера выше я хотел бы иметь переменную, содержащую следующее:
./Dir1/Sub2/
./Dir1/Sub1/
./Dir3/
Это не должно возвращаться ./Dir1/Sub1/
потому что это не имеет a Sub1.txt
файл.
Это возврат shoudn't ./Dir2/Sub2/
потому что txt файл в нем не Sub2.txt
.
Это не должно возвращаться ./Dir4/
или ./Dir4/Sub1/
потому что Dir4.txt
не находится непосредственно в ./Dir4/
.
Примечание:
Названия каталогов не должны быть этими именами в частности. То, что важно, - то, что имя txt файла соответствует содержанию названия каталога.
Кроме того, я знаю, что другие языки могли бы быть легче, но мне нужен он в ударе.
Учитывая
$ tree somepath/
somepath/
├── Dir1
│ ├── Sub1
│ │ └── Sub1.jpg
│ └── Sub2
│ ├── Sub2.jpg
│ ├── Sub2.png
│ └── Sub2.txt
├── Dir2
│ ├── Sub1
│ │ ├── Sub1.doc
│ │ └── Sub1.txt
│ └── Sub2
│ ├── SomeTxt.txt
│ ├── Sub2.jpg
│ └── Sub2.png
├── Dir3
│ └── Dir3.txt
└── Dir4
├── Some.txt
└── Sub1
└── Dir4.txt
9 directories, 12 files
тогда, с включенной опцией оболочки globstar (shopt -s globstar
)
for d in somepath/**/; do
d="${d%/}"
[[ -f "${d}/${d##*/}.txt" ]] && printf "%s\n" "$d"
done
somepath/Dir1/Sub2
somepath/Dir2/Sub1
somepath/Dir3
Если вы хотите сохранить результаты в массиве для дальнейшего использования обработки, вы можете сделать это, используя встроенную в оболочку mapfile
(или ее синоним readarray
), например,
mapfile -t TXT_DIRS < <(
for d in somepath/**/; do
d="${d%/}"
[[ -f "${d}/${d##*/}.txt" ]] && printf "%s\n" "$d"
done
)
ПРИМЕЧАНИЕ: было бы лучше завершить список нулем, используя один из методов, описанных в bash: безопасное для пробелов процедурное использование find into select
Затем вы можете перебирать массив таким образом
for d in "${TXT_DIRS[@]}"; do
echo "$d"
done
somepath/Dir1/Sub2
somepath/Dir2/Sub1
somepath/Dir3
В качестве альтернативы, вы можете вообще не сохранять результаты и просто обрабатывать каждый каталог так, как вы его находите, т.е. 1115]
for d in somepath/**/; do
d="${d%/}"
[[ -f "${d}/${d##*/}.txt" ]] && echo "Doing something with $d"
done
Doing something with somepath/Dir1/Sub2
Doing something with somepath/Dir2/Sub1
Doing something with somepath/Dir3
Это - практически то же как ответ steeldriver, но это циклично выполняется по каждому txt файлу вместо по каждому dir, Надо надеяться, легче понять также.
, Так как Вы упомянули в комментарии, что Вам на самом деле не нужен массив, я не учел тот шаг.
shopt -s globstar
for f in ./**/*.txt; do
d="$(dirname "$f")"
if [[ $(basename "$f") == $(basename "$d").txt ]]; then
printf '%s\n' "$d"
fi
done
Вывод:
./Dir1/Sub2
./Dir2/Sub1
./Dir3