假设我有以下目录结构,其中目录的名称无关紧要:
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 的
globstar
shell 选项启用递归文件模式匹配 - 注意
_
参数:进入 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.mkdir
和print
。如果您想复制并粘贴,请执行以下操作:
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
其他设置)。这没问题。
上述内容假设您使用的是伯恩风格的外壳喜欢bash
,dash
/sh
,ksh
,zsh
,posh
, 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
。