因此,我有一个这样的目录结构:
parent/
├── sub1
│ └── source
│ └── file1
│ └── file2
├── sub2
│ └── sub2.1
│ └── source
│ └── something1
│ └── something2
└── sub3
└── sub3.1
└── sub3.1.1
└── source
└── other.zip
我想搬家全部文件(文件名不同)来自所有目录均已命名source
到其相对上级/父目录。因此,结果应该是这样的:
parent/
├── sub1
│ ├── file1
│ ├── file2
│ └── source
├── sub2
│ └── sub2.1
│ ├── something1
│ ├── something2
│ └── source
└── sub3
└── sub3.1
└── sub3.1.1
├── other.zip
└── source
有没有简单的方法(一句话) 来完成此操作,也许使用find
命令?最好是一个不太复杂以至于我难以理解的命令。:D 我对 Linux 还很陌生。
编辑:我还将利用该解决方案编写一个 bash 脚本(以便我可以轻松使用它)。例如:./movefiles.sh myfolder
因此,最好该解决方案可以轻松容纳变量,尤其是那些带有符号的变量.
(如果它是隐藏目录),,,#
等等@
。
答案1
启用选项的简单for
循环globstar
(运行shopt -s globstar
即可执行)将完成该工作:
dirname="source"
for i in ./**/"$dirname"/; do
mv "$i"* "${i%$dirname/}"
done
这GNUparallel
该循环的等效项是:
parallel mv {}* {//}/ ::: ./**/"$dirname"/
一种完全不同的方法是rename
从字符串中删除“$dirname/”部分:
rename "s/$dirname\///" **/"$dirname"/*
引用$
像我在这里一样使用双引号可以保留除、`
和\
之外的每个特殊字符的含义!
。如果要在上述任何解决方案中包含“隐藏”点文件,请dotglob
在运行之前设置选项:shopt -s dotglob
解释
globstar
如果设置,路径名扩展上下文中使用的模式**
将匹配所有文件和零个或多个目录和子目录。如果模式后跟/
,则仅匹配目录和子目录。
./**/source/
匹配source
当前目录下的每个目录,该mv
命令将目录内部的每个文件移动到其父目录 -是一个参数扩展,它从(路径)字符串的末尾${i%source/}
删除字符串。source/
示例运行
$ tree
.
├── sub1
│ └── source
│ ├── file1
│ └── file2
├── sub2
│ └── sub2.1
│ └── source
│ ├── something1
│ └── something2
└── sub3
└── sub3.1
└── sub3.1.1
└── source
└── other.zip
$ dirname="source"
$ for i in ./**/"$dirname"/; do mv "$i"* "${i%$dirname/}"; done
$ tree
.
├── sub1
│ ├── file1
│ ├── file2
│ └── source
├── sub2
│ └── sub2.1
│ ├── something1
│ ├── something2
│ └── source
└── sub3
└── sub3.1
└── sub3.1.1
├── other.zip
└── source
答案2
如果你想要一个find
解决方案,你可以使用这个:
find parent -name "source" -type d -exec bash -c 'cd "$1"; mv * ..' bash {} \;
解释:
find parent -name "source" -type d
source
- 对于以parent
...命名的每个目录-exec bash -c '...' bash {} \;
- 使用bash
as调用 Bash$0
,并将目录路径作为$1
cd "$1"; mv * ..
- cd 进入目录;将其所有内容上移一级。- 选择:
mv "$1"/* "$1/.."
- 选择:
这或多或少基于甜点的答案。
包括隐藏文件
find parent -name "source" -type d -exec bash -c 'shopt -s dotglob; cd "$1"; mv * ..' bash {} \;
shopt -s dotglob
- 使 glob 包含隐藏文件
答案3
您可以使用下面的代码来获得您想要的内容:
dir=$(find . -name 'source' | sed s:source::)
for path in $dir; do
mv "$path"source/* "$path"
done
该find
命令返回从父目录到源目录的目录路径。其中find . -name 'source'
“.”代表父目录,“源”代表要查找的子目录。
该命令从命令结果中sed
删除。source
find
剩下的只是迭代(for
)和移动命令(mv
)
答案4
嵌套的 find 命令将在一行中完成该任务,但这可能看起来有点古怪。;-)
具体来说:
find . -name source -type d -exec sh -c 'find "$0" -type f -execdir mv "{""}" .. \;' {} \;
解释:
find . -name source -type d
source
查找当前 (.
) 目录中命名的所有目录。-exec sh -c '...' {} \;
对每个找到的目录执行sh
with 命令'...'
,将目录名插入到 中{}
,并进一步使用 的内容定义执行sh
的 变量(请参阅手册页中的选项)$0
{}
-c
sh
的参数
sh -c
,'find "$0" -type f ... '
查找目录内的所有文件$0
最后
... -execdir mv "{""}" ..
将找到的文件{}
(此处隐藏以"{""}"
防止由于上游而导致的替换-exec
)移动到(目录本地 - 因此-execdir
)父目录..
示例运行:
marcus@gargabuntu:~/temp$ tree
.
├── sub1
│ └── source
│ ├── file1
│ └── file2
├── sub2
│ └── sub2.1
│ └── source
│ ├── something1
│ └── something2
└── sub3
└── sub3.1
└── sub3.1.1
└── source
└── other.zip
9 directories, 5 files
marcus@gargabuntu:~/temp$ find . -name source -type d -exec sh -c 'find "$0" -type f -execdir mv "{""}" .. \;' {} \;
marcus@gargabuntu:~/temp$ tree
.
├── sub1
│ ├── file1
│ ├── file2
│ └── source
├── sub2
│ └── sub2.1
│ ├── something1
│ ├── something2
│ └── source
└── sub3
└── sub3.1
└── sub3.1.1
├── other.zip
└── source
9 directories, 5 files