如何使用命令行在最后的目录中递归创建目录?

如何使用命令行在最后的目录中递归创建目录?

假设我有以下目录结构,其中目录的名称无关紧要:

currentDir/
   Dir1
      Dir1
         Dir1 *
      Dir2 *
      Dir3 *
   Dir2
      Dir1 *
      Dir2 
         Dir1*
   Dir3*

有没有办法让我只在树枝末端的目录中创建一个名为“Texture”的目录(在示例中,它们标有*)。我希望只有这些目录才能获得Texture目录,而其他目录则不能。

所有目录可能有或可能没有文件,但最终目录中不会有任何其他目录。

答案1

首先开启递归遍历

shopt -s globstar

现在我们可以使用 来查看所有目录**。要取消设置,您可以使用shopt -u globstar(默认情况下它是关闭的,因此当您打开新 shell 时它将关闭)。

在以下所有内容中,echo测试后删除以实际创建目录。

如果树末端的目录为空,则可以测试其是否为空,并且只有在检测到时才创建目录……例如

for d in **/; do [[ -z "$(ls -Aq "$d")" ]] && echo mkdir "$d"Texture; done

即如果输出ls -A (hidden files except current and parent dir) -q (printing ? for non-printing characters)为空,则创建一个目录。

但由于目录包含文件,我们最好测试一下是否存在目录

for d in **/; do [[ -z "$(find "$d" -maxdepth 1 -mindepth 1 -type d)" ]] && echo mkdir "$d"Texture; done

mindepth -1是阻止找到当前目录...find看到隐藏文件,所以我们知道这些文件已包含在内。由于任何字符都应该通过测试(我们只想检查输出是否为空),所以这应该是相当安全的...

更简洁的方法(对不起,格雷格)(但实际上所有这些方法都做了一些类似的不确定的事情 - 我们几乎可以使用文件名作为文本,因为我们实际上并没有尝试对这些文件本身进行任何操作):

for d in **/; do (ls -Alq "$d" | grep -q '^d') || echo mkdir "$d"Textures; done

这里我们添加了-l长输出标志,以以下形式打印每个文件

drwxrwxr-x 5 zanna zanna 4096 Sep 27 22:00 Dir1

然后我们吞咽将这些东西导入管道,grep看看是否有任何行以 开头d(意味着有一个目录)。我们不想grep打印任何毫无意义的不可靠的文本,所以我们只需检查其退出状态以-q查看它是否找到任何东西。如果没有,我们创建一个目录(使用||或运算符,意思是,如果上一个命令失败,则执行下一个命令)。实际上,即使您的文件名包含换行符等可怕的字符,这也应该有效,因为每行都ls将它们打印为?-应该以表示文件类型的字母开头,因此,可能不会有小猫死亡。

答案2

这是一个痛苦的find -exec呼声

前:

$ tree currentDir
currentDir
├── Dir1
│   ├── Dir1
│   │   └── Dir1
│   ├── Dir2
│   └── Dir3
├── Dir2
│   ├── Dir1
│   └── Dir2
│       └── Dir1
└── Dir3

创建纹理目录

$ find currentDir -depth -type d -exec bash -c 'cd "$1"; shopt -s globstar nullglob; texture=(**/Texture); [[ ${#texture[@]} -eq 0 ]] && mkdir Texture' _ '{}' \;

这取决于:

  • find-depth启用深度优先导航的选项
  • bash 的globstarshell 选项启用递归文件模式匹配
  • 注意_参数:进入 bash var $0,以便 find 的当前路径名可以是 bash var$1

$ tree currentDir
currentDir
├── Dir1
│   ├── Dir1
│   │   └── Dir1
│   │       └── Texture
│   ├── Dir2
│   │   └── Texture
│   └── Dir3
│       └── Texture
├── Dir2
│   ├── Dir1
│   │   └── Texture
│   └── Dir2
│       └── Dir1
│           └── Texture
└── Dir3
    └── Texture

答案3

这应该有效:

shopt -s globstar; for i in **/; do sub=$(find "$i" -type d | wc -l); if [[ "$sub" -eq 1 ]]; then mkdir "$i"/Texture; fi;done

结果:

currentDir
├── Dir1
│   ├── Dir1
│   │   └── Dir1
│   │       └── Texture
│   ├── Dir2
│   │   └── Texture
│   └── Dir3
│       └── Texture
├── Dir2
│   ├── Dir1
│   │   └── Texture
│   └── Dir2
│       └── Dir1
│           └── Texture
└── Dir3
    └── Texture

答案4

Python使这变得容易。

python3 -c 'import os
for d in [root for root, dirs, files in os.walk(".") if not any(dirs)]:
    os.mkdir(d + "/Texture")'

您可以从 shell 运行该命令。它将三行脚本传递给Python 3 解释器.,运行它。该脚本会构建(您所在的目录)下的所有目录的列表,然后Texture在每个尚无子目录的目录中创建一个子目录。

与大多数其他方法相比,这种方法更容易编写,也更容易理解,因为 Python 有一个os.walk函数以一种容易看出哪些目录有子目录的方式枚举目录(更普遍的原因是 Python 是一种许多用户觉得干净直观的语言)。

如果你只想展示将创建哪些新目录,而不是实际创建它们,而是替换os.mkdirprint如果您想复制并粘贴,请执行以下操作:

python3 -c 'import os
for d in [root for root, dirs, files in os.walk(".") if not any(dirs)]:
    print(d + "/Texture")'

有多种方法可以将这三行命令写在一行上,但没有必要。您可以在交互式 shell 提示符下通过键入或粘贴来输入要使用的命令,也可以在 shell 脚本中使用它。以交互方式输入时,您的 shell 将在第二行和第三行的开头打印>(除非您进行了$PS2其他设置)。这没问题。

上述内容假设您使用的是伯恩风格的外壳喜欢bashdash/shkshzshposh, ETC。 (那些 答案使用。该命令是 Bash 特有的,尽管shopt -s globstar其他一些贝壳也有类似的特征。所以如果它们对你有用,这个也应该有用。)如果你正在使用 Ubuntu,并且你不知道你在哪个 shell 中输入命令,它是bash. 如果您使用csh或者tcsh,您必须\在前两行末尾放置一个以避免Unmatched '.错误,然后您会看到?而不是>

要在现有目录层次结构上测试此方法而不创建目录,只需使用上面描述的第二个命令。但是,如果您愿意,您可以在某个地方创建一个新的目录层次结构,仅用于测试目的。mkdir -p dir/{a/{b/c,d,e},f/{g,h/i},j}创建一个与示例中的拓扑结构相同的目录树;find dir -type d -exec touch {}/x \;用一些文件填充它,以便您可以检查非目录的存在是否没有问题;cd dir进入它;然后您可以测试上面显示的命令,以及您可能感兴趣的任何其他方法,例如其他答案中介绍的方法;然后运行tree

相关内容