基本上,给定一个父目录 (PARENT),包含 1..M 个目录 (DIRA-DIRZ),每个目录包含 0..N 个目录 (DIR1-DIRN),每个目录包含一个文件列表 (FILEa-FILEz)。 。
PARENT/DIRA/DIR1/files
PARENT/DIRB/files
PARENT/DIRC/DIR2/files
PARENT/DIRC/DIR3/files
...如果二级目录(DIR1-DIRN)存在,则将文件从二级目录(DIR1)移动到包含它的一级目录(DIRA),然后删除现在空的二级目录(DIR1) )。
PARENT/DIRA/files
PARENT/DIRB/files
PARENT/DIRC/files
我发现我正在尝试使用这个片段:
find /thisdir -type f -name "*.ogg" -exec mv {} /somedir \;
但我无法弄清楚外循环以及如何集成它们。
您能提供的任何帮助,尤其是一些解释,都将非常出色!
答案1
由于几乎所有 Linux 发行版(至少是主要发行版)都预装了 Python,因此编写一个简单的 Python 脚本可能会更容易。
#!/usr/bin/env python3
import sys
from pathlib import Path
def flatten_and_del(targdir):
pardir = targdir.parent
for f in targdir.glob("*"):
f.rename(pardir / f.name)
targdir.rmdir()
def process_dir(parent):
parent = Path(parent)
if not parent.is_dir():
raise RuntimeError(f"{parent} is not a directory!")
for f in parent.glob("*"):
if not f.is_dir():
continue
flatten_and_del(f)
if __name__ == "__main__":
process_dir(sys.argv[1])
将其另存为,例如,tidy-dirs.py
并像这样运行:
python3 tidy-dirs.py path/to/PARENT
警告:正如 αГsнιη 在他们的评论中提到的,这种方法将要如果文件名冲突会导致数据丢失。如果您不希望发生这种情况,请在执行之前flatten_and_del
添加target.exists()
检查.rename()
答案2
和zsh
:
autoload zmv # best in ~/.zshrc
zmv '(PARENT)/(*)/*/(*)(#qD)' '$1/$2/$3'
rmdir PARENT/*/*(#qD/^F)
答案3
实际上这是两个命令。第一个是mv
上一级的文件,第二个是删除空目录。
(这两个命令都连接在一起,&&
使其看起来像一行)
find -H PARENT -mindepth 3 ! -type d -execdir cp --backup=numbered -al {} .. \; -delete && find -H PARENT -depth -mindepth 2 -type d -exec rmdir {} +
而不是mv
创建硬链接并删除源。cp
提供内置备份解决方案:
cp--backup=numbered
将自动重命名文件,以防另一个文件已存在
cp-l
创建硬链接而不是复制
cp-a
保留元数据(mtime、权限)
find-delete
递归删除所有内容(谨慎使用)
所有find
论点均已解释:
-H
如果 PARENT 是符号链接,则查找
查找与(= 反转参数)! -type d
相同只 查找第 3 级的 */*/*/ 文件(用于使其更安全)从子目录 查找运行命令-type f
!
-mindepth 3
-maxdepth 3
-execdir
\;
和之间的区别+
解释:
找到-exec CMD {} \;
CMD ARG1的串行1:1执行;命令 ARG2; ... (其中 ARG 是 find 的结果)
find-exec CMD {} +
并行执行 CMD ARG1 ARG2 ARG3 ... ARGN;
PARENT
您可以替换"$@"
并创建一个小 shell 脚本,该脚本将在多个参数上运行,而不是从终端运行。
sh ./myscript.sh PARENT [PARENT2...]
运行脚本
#!/bin/sh
test -e "$1" || exit 1
find -H "$@" -mindepth 3 ! -type d -execdir cp --backup=numbered -al {} .. \; -delete
find -H "$@" -depth -mindepth 2 -type d -exec rmdir {} +
答案4
如果您有很多目录需要执行此操作,则可以使用简单的 bash 脚本轻松解决此问题,以节省时间。
只有一个目录:
parent/
└── DIRA
└── DIR1
├── file1.ogg
├── file2.ogg
└── file3.ogg
然后,在 DIR1 内部:
# You can also use ; over && but the second one is more reliable,
# specially if you are doing this in a remote server.
mv *.ogg ../ && cd ../ && rmdir DIR1/
结果:
parent/
└── DIRA
├── file1.ogg
├── file2.ogg
└── file3.ogg
如果您确定二级目录中的所有文件都是.ogg,则可以使用MV *代替MV *.ogg。