假设我有以下内容:
./
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
使用 bash(在我的情况下是 bashrc),如何获取包含所有包含与包含目录同名的文本文件(.txt)的目录的变量?因此,从上面的示例中,我希望有一个包含以下内容的变量:
./Dir1/Sub2/
./Dir1/Sub1/
./Dir3/
它不应该返回,./Dir1/Sub1/
因为它没有Sub1.txt
文件。
它不应该返回,./Dir2/Sub2/
因为其中的 txt 文件不是Sub2.txt
。
它不应该返回./Dir4/
或./Dir4/Sub1/
因为Dir4.txt
不是直接在./Dir4/
。
笔记:
目录名称不必特别为这些名称。重要的是 txt 文件的名称与包含目录的名称相匹配。
另外,我知道其他语言可能更容易,但我需要在 bash 中使用它。
答案1
鉴于
$ 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
然后,启用 shell 的 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
如果要将结果存储在数组中以供以后处理,则可以使用 shell 的内置函数mapfile
(或其同义词readarray
)来实现,例如
mapfile -t TXT_DIRS < <(
for d in somepath/**/; do
d="${d%/}"
[[ -f "${d}/${d##*/}.txt" ]] && printf "%s\n" "$d"
done
)
笔记: 更好的做法是使用在 bash:在 select 中使用 find 进行空格安全程序化
然后你可以像这样迭代数组
for d in "${TXT_DIRS[@]}"; do
echo "$d"
done
somepath/Dir1/Sub2
somepath/Dir2/Sub1
somepath/Dir3
或者,您可以完全避免存储结果,只需在找到每个目录时对其进行处理,即
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
答案2
这实际上与steeldriver的答案相同,但它循环遍历每个txt文件而不是每个目录。希望它也更容易理解。
由于您在评论中提到您实际上并不需要数组,因此我省略了该步骤。
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