我有一个具有复杂文件夹结构的文件夹:
├── folder1
│ ├── 0001.jpg
│ └── 0002.jpg
├── folder2
│ ├── 0001.jpg
│ └── 0002.jpg
├── folder3
│ └── folder4
│ ├── 0001.jpg
│ └── 0002.jpg
└── folder5
└── folder6
└── folder7
├── 0001.jpg
└── 0002.jpg
我想展平文件夹结构,以便所有文件都驻留在具有唯一名称的父目录中,例如folder1_0001.jpg、folder1_0002.jpg...folder5_folder6_folder7_0001.jpg 等。
我尝试使用中建议的代码“扁平化文件夹结构”
$ find */ -type f -exec bash -c 'file=${1#./}; echo mv "$file" "${file//\//_}"' _ '{}' \;
表明echo
它正在工作:
mv folder3/folder4/000098.jpg folder3_folder4_000098.jpg
但输出文件不会放置在父目录中。我搜索了整个驱动器,但找不到输出文件。
$ find . -type f -name "*.jpg" | sed 'h;y/\//_/;H;g;s/\n/ /g;s/^/cp -v /' | sh
-v
表明它正在工作:
‘./folder3/folder4/000098.jpg’ -> ‘._folder3_folder4_000098.jpg’
然而,输出会在父目录中创建隐藏文件,这使我的工作流程变得复杂。我可以使用查看父目录中的这些隐藏文件ls -a
我还尝试了下面的建议代码“使用拼合文件夹命令重命名重复文件”
find . -mindepth 2 -type f | xargs mv --backup=numbered -t . && find . -type d -empty -delete
但该命令会覆盖具有相似文件名的文件。
关于如何扁平化复杂的文件夹结构而不覆盖具有相似名称的文件有什么建议吗?当前的解决方案似乎只适用于一层深的文件夹结构。
我的最终目标是将唯一名称转换为连续数字,如中所述“将文件夹中的文件重命名为连续编号”
a=1
for i in *.jpg; do
new=$(printf "%04d.jpg" "$a") #04 pad to length of 4
mv -- "$i" "$new"
let a=a+1
done
答案1
我不知道为什么你的问题中的第一个解决方案不起作用。我只能假设你忘记删除echo
.尽管如此,假设您正在运行,这里还有另一种方法也应该可以满足您的需要bash
:
shopt -s globstar
for i in **/*jpg; do mv "$i" "${i//\//_}"; done
解释
- 打开
shopt -s globstar
bash 的globstar
功能,该功能可以**
递归地匹配任意数量的目录或文件。 for i in **/*jpg;
将迭代名称以 结尾的所有文件(或目录).jpg
,并将每个文件保存为$i
."${i//\//_}"
是当前文件(或目录)的名称,其中所有实例都/
替换为_
.
如果您还可以拥有名称结尾的目录.jpg
并希望跳过它们,请改为执行以下操作:
shopt -s globstar
for i in **/*jpg; do [ -f "$i" ] && echo mv "$i" "${i//\//_}"; done
对于所有文件,无论扩展名如何:
shopt -s globstar
for i in **/*; do [ -f "$i" ] && echo mv "$i" "${i//\//_}"; done
答案2
如果您有 Perl rename
(有时称为prename
),您可以执行以下操作:
find folder* -type f -name '*.jpg' -exec rename 's!/!_!g' {} \;
这将获取每个文件名路径并将所有出现的 替换/
为_
。
如果您确实想将文件重命名为一系列连续的四位数字文件名,您可以在原始数据集上使用它。它仅在目录和文件名包含常规字母数字的情况下起作用(具体来说,如果存在空格、shell 标点符号或其他空格,它将失败):
rename 's!.*!sprintf "%04d.jpg", ++$a!e' $(find folder* -type f -name '*.jpg' | sort)
用于rename -n ...
查看更改任何内容后会发生什么,或用于rename -v ...
观察它运行时发生的情况。
答案3
pax -rws'|/|_|g' folder*/ .
...只要无法重叠文件名就可以工作。为了更安全地执行此操作,请使用-l
链接选项并将树镜像到另一个路径,然后在删除旧树之前检查新树。
答案4
我使用以下脚本成功了:
#!/bin/sh
for folder in $(ls $1)
do
for file in $(ls ${folder})
do
mv ${folder}/${file} $1/${folder}_${file}
done
rmdir ${folder}
done