我知道如何查找具有给定名称的所有目录:
find . -name unnecessary_dir_level
以及如何将文件移动到父目录:
mv * ..
我如何组合事物 - 是
find . -name unnecessary_dir_level -exec mv {}/* {}/.. \;
要在不造成混乱的情况下完成这项工作吗?或者什么会?我不热衷于在没有建议的情况下尝试这个(并且目录太大,无法在合理的时间内备份)。
答案1
通过支持(无破坏)选项的实现zsh
,您可以执行以下操作:mv
-n
for dir (**/unnecessary_dir_level(ND/od)) () {
(( ! $# )) || mv -n -- $@ $dir:h/ && rmdir -- $dir
} $dir/*(ND)
在哪里:
for var (values) cmd
是循环的简短版本(在编程语言中更常见)for
。**/
: 一个全局运算符,这意味着任何级别的子目录N
glob 限定符:启用nullglob
该 glob(如果没有匹配,请不要抱怨)D
glob 限定符:启用dotglob
该 glob(包括隐藏文件)/
glob 限定符:限制为文件类型目录。od
glob 限定符:o
rder byd
epth (在它们所在的分支之前离开)() { body; } args
: 带有参数的匿名函数。- 这里参数being
$dir/*(ND)
:所有文件,包括隐藏的文件$dir
- 这身体在这些文件上运行
mv
(如果有),然后在现在应该为空的rmdir
文件上运行。$dir
$dir:h
,(它的目录名,如 csh 中的)h
的开头。$dir
请注意,这mv * ..
两个帐户是错误的:
- 它缺少选项分隔符:
mv -- * ..
- 您缺少隐藏文件:
mv -- *(D) ..
在 zsh 中,((shopt -s nullglob failglob; exec mv -- * ..)
在bash
) - 另外:如果父级中存在同名文件,您最终可能会丢失数据。
find . -name unnecessary_dir_level -exec mv {}/* {}/.. \;
无法工作,因为{}/*
glob 在调用之前已由 shell 展开mv
。如果当前目录中有调用的目录,它只会扩展为某个内容{}
,然后移动错误的文件。
你可以用find
and bash
with 做类似的事情:
find . -depth -name unnecessary_dir_level -type d -exec \
bash -O nullglob -O dotglob -c '
for dir do
set -- "$dir"/*
(( ! $# )) || mv -n -- "$@" "${dir%/*}" && rmdir -- "$dir"
done' bash {} +
答案2
版本bash
>= 4.0:
shopt -s globstar nullglob dotglob
for f in **/name/; do echo mv "$f"* "$f"..; done
如果输出看起来没问题,则删除echo
.
从man bash
:
globstar
:如果设置,路径名扩展上下文中使用的模式 ** 将匹配所有文件以及零个或多个目录和子目录。如果模式后跟 /,则仅目录和子目录匹配。
nullglob
:如果设置,bash 允许不匹配文件的模式[...] 扩展为空字符串,而不是它们本身。
dotglob
:如果设置,bash 包含以“.”开头的文件名在路径名扩展的结果中。
答案3
您可以使用for loop
将每个找到的目录的内容移动到上一级。例如,我的目录temp
中有文件abc
。
tmp/abc/
└── temp
以下命令将放入目录temp
中tmp
:
for i in ` find . -name abc ` ; do mv $i/* $i/.. ; done