递归重命名所有文件而不更改其扩展名?

递归重命名所有文件而不更改其扩展名?

如何在不改变扩展名的情况下递归重命名几层子目录中的所有文件?

下面是我所拥有的内容的简化版本(以节省空间)。为了便于论证,我希望所有文件都具有相同的标题,但保留其原始扩展名。每个目录绝不会超过一个文件,因此不可能出现重复的情况。

为了简单起见,我们将它们全部称为foo,然后是它们当前的扩展名。

所以只是澄清一下:
Asset\ 1.pdf, Asset\ 1.png, , 将变成:, , , 等等。Asset\ [email protected]Asset\ 1.svg

foo.pdffoo.pngfoo.pngfoo.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,以便您可以使用参数扩展,提取目录PARENTEXTENSION以便您可以构造新文件名,然后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

添加-nmv避免覆盖现有文件(如果有)。

这也可以通过 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 等。

相关内容