我正在尝试从 Mac 上的终端(在 bash 上运行)删除几个子文件夹。子文件夹以相同的两个字母“na”开头,我编写了如下代码:
if [[ -d "$base/${subject}/${session}/"na* ]]; then
echo "removing na folder from all folders"
rm -rf "$base/${subject}/${session}/"na*
我尝试了各种不同的方法来编写它(使用括号内和括号外的 *、括号内和括号外的 na 等等)。当我运行代码时,它不会回显消息,因此找不到文件夹。在阅读了类似问题的答案后(删除 Mac OS X 上不支持通配符的 rm 命令) 我做了一个“while 循环”来确保它不会在一个文件夹后停止,但问题仍然存在,即“na*”文件夹首先找不到。如果我用一个确切的子文件夹名称替换 *,它就可以工作了。但这相当不方便。
希望有人能帮忙!
编辑:
谢谢你们两位的回复。Maciorowski 的代码片段起了作用,解决了问题!也非常感谢你们的教育性回答。不知道 [[ 和 * 的警告。
答案1
[[
和之间的单词]]
不经过 […] 文件名扩展。您的第一个*
没有展开。显然没有名为(字面上)的子目录na*
,测试失败,因此rm
未执行。
如果rm
要进行的话,*
会先进行扩展。
诊断另一个答案“[第一个]na*
将扩展为多个名称”是错误的。na*
它根本没有扩展。
如果你使用[ -d …/na* ]
而不是[[ -d …/na* ]]
那么na*
将会被扩展和然后您可能会得到几个路径名([
会打印错误)。[
并且[[
不等同。
rm -rf "$base/${subject}/${session}/"na*
有点缺陷。由于rm
不是 Bash 的内置命令,因此扩展后的行可能太长,你可能会得到Argument list too long
。链接指向一个包含两种不同解决方案的答案:带有for
和find
。针对您的情况量身定制的解决方案示例for
可能是:
( shopt -s nullglob
mark=
for d in "$base/$subject/$session/"na*/; do
[ -z "$mark" ] && { mark=1; echo "Removing \`na*' directories from \`$base/$subject/$session/'" >&2; }
echo rm -rf "$d"
done )
(故障安全,试运行。如果结果看起来不错,则替换echo rm
为。)rm
笔记:
- 尾随的反斜杠
na*/
使模式仅匹配目录。 shopt -s nullglob
是万一na*/
匹配零个目录。通常情况下,匹配零个的模式将保持原样;当nullglob
它扩展为零个单词时,我们的循环就变成for d in; do …
,并且其主体执行零次。- 您的原始消息 (
removing na folder from all folders
) 具有误导性。我的代码和您的原始代码都没有尝试“从文件夹中删除文件夹”。$base/$subject/$session/
不能是“文件夹s“。我更改了信息。 - 我操纵
mark
仅在需要时回显消息,并且仅回显一次。看来这就是你想要的。 - 对我来说,该消息看起来具有“诊断性”,因此
>&2
。 - 该代码片段在子 shell 中运行。要点是
nullglob
,mark
和d
是 shubshell 本地的,不会影响任何其他内容。
答案2
您期望na*
会扩展为多个名称,但据我所知,-d
测试只接受一个参数。此外,正如另一个答案所指出的那样,内部没有发生任何扩展[[ ]]
。
一种解决方案是迭代find
:
find "$base/${subject}/${session}" -mindepth 1 -maxdepth 1 -type d -name "na*" -exec rm -rf {} \;
如果你想从基础开始递归删除树结构中的所有“na*”文件夹:
find "$base" -type d -name "na*" -exec rm -rf {} \;