如何在不改变扩展名的情况下递归重命名几层子目录中的所有文件?
下面是我所拥有的内容的简化版本(以节省空间)。为了便于论证,我希望所有文件都具有相同的标题,但保留其原始扩展名。每个目录绝不会超过一个文件,因此不可能出现重复的情况。
为了简单起见,我们将它们全部称为foo
,然后是它们当前的扩展名。
所以只是澄清一下:
Asset\ 1.pdf
, Asset\ 1.png
, , 将变成:, , , 等等。Asset\ [email protected]
Asset\ 1.svg
foo.pdf
foo.png
foo.png
foo.svg
我通常会使用参数扩展和for
循环,例如:
for f in */*; do mv "$f" "${f%/*}/foo.${f##*.}"; done
但它不是递归的。所以我更愿意使用find
..-exec
或类似的东西。
~/Desktop/Project/Graphics/
├── Huge
│ ├── PDF
│ │ └── Asset\ 1.pdf
│ ├── PNG
│ │ ├── 1x
│ │ │ └── Asset\ 1.png
│ │ └── 4x
│ │ └── Asset\ [email protected]
│ └── SVG
│ └── Asset\ 1.svg
├── Large
│ ├── PDF
│ │ └── ProjectAsset\ 2.pdf
│ ├── PNG
│ │ ├── 1x
│ │ │ └── ProjectAsset\ 2.png
│ │ └── 4x
│ │ └── ProjectAsset\ [email protected]
│ └── SVG
│ └── ProjectAsset\ 2.svg
├── Medium
│ ├── PDF
│ │ └── ProjectAsset\ 3.pdf
│ ├── PNG
│ │ ├── 1x
│ │ │ └── ProjectAsset\ 3.png
│ │ └── 4x
│ │ └── ProjectAsset\ [email protected]
│ └── SVG
│ └── ProjectAsset\ 3.svg
├── Small
│ ├── PDF
│ │ └── ProjectAsset\ 4.pdf
│ ├── PNG
│ │ ├── 1x
│ │ │ └── ProjectAsset\ 4.png
│ │ └── 4x
│ │ └── ProjectAsset\ [email protected]
│ └── SVG
│ └── ProjectAsset\ 4.svg
└── Tiny
├── PDF
│ └── Asset\ 5.pdf
├── PNG
│ ├── 1x
│ │ └── Asset\ 5.png
│ └── 4x
│ └── Asset\ [email protected]
└── SVG
└── Asset\ 5.svg
30 directories, 20 files
答案1
它与以下非常相似find...-exec
:调用 shell,以便您可以使用参数扩展,提取目录PARENT
,EXTENSION
以便您可以构造新文件名,然后PARENT/NAME.EXTENSION
移动/重命名:
find target_dir -name '?*.*' -type f -exec sh -c '
ret=0
for file do
head=${file%/*}
mv -- "$file" "$head/NAME.${file##*.}" || ret=$?
done
exit "$ret"' sh {} +
如果您想空运行上述内容,请在...echo
之前插入mv
请注意,它还会处理隐藏文件。
如果您有权访问,zsh
则可以运行:
autoload zmv
zmv -n '(**/)(*.*)' '${1}NAME.${2:e}'
-n
如果您对结果满意,请删除。
(#qD)
默认情况下会跳过隐藏文件,但如果您希望处理它们,可以使用glob 限定符:
autoload zmv
zmv -n '(**/)(?*.*)(#qD)' '${1}NAME.${2:e}'
答案2
如果使用 bash,您的想法可以遍历所有目录:
$ shopt -s globstar
$ for f in ./Desktop/**/*; do [[ -f $f ]] &&
mv -n "$f" "${f%/*}/foo.${f##*.}"; done
添加-n
以mv
避免覆盖现有文件(如果有)。
这也可以通过 find 来完成(在一调用 shell(比每个文件调用一个 shell 更快):
$ find ./Desktop -type f -exec sh -c '
for f; do echo mv -n "$f" "${f%/*}/foo.${f##*.}"; done' findsh {} \+
echo
如果该命令满足您的需要,请删除。
答案3
也许我过于简单化了,但是,如果您知道目录层次结构的最大深度(此处:3),为什么不呢
for f in */* */*/* */*/*/*; do ... ; done
添加一些错误检查?
答案4
find ~/Desktop/Project/Graphics/ -type f -exec sh -c 'f={}; mv $f ${f%/*}/foo.${f##*.}' \;
sh
表示调用默认 shell。您可以将其更改为 bash、zsh 等。