在 bash/terminal 中批量重命名文件夹及其文件

Mass rename folders and their files in bash/terminal

我正在尝试使用命令 "mv" 批量重命名文件夹及其各自的文件,但进展不顺利,我希望将文件夹重命名为:

1/
2/
3/

等等

每个文件夹中的文件在此过程中也应重命名,同时保留其文件扩展名。

1.png
2.gif
3.jpg

等等

非常感谢您的帮助

是单级目录吗?或者你有子目录吗?

是这样的吗?

之前:

.
├── folderE
│   ├── conf.properties
│   ├── omg.avi
│   └── test-diff.diff
├── folder_a
│   ├── first.png
│   ├── main.jpg
│   └── second.gif
├── folder_d
│   ├── another.zip
│   └── one.mpeg
└── with space
    └── file with spaces too.mov

命令:

countDir=1
for dir in *; do
  cd "$dir"; 
  countFile=1

  for file in *; do 
    mv "$file" $countFile.${file#*.}
    ((countFile++))
  done

  cd ..
  mv "$dir" $countDir
  ((countDir++))
done

或者,一行相同:

countDir=1; for dir in *; do cd "$dir"; countFile=1; for file in *; do mv "$file" $countFile.${file#*.}; ((countFile++)); done; cd ..; mv "$dir" $countDir; ((countDir++)); done

之后:

.
├── 1
│   ├── 1.properties
│   ├── 2.avi
│   └── 3.diff
├── 2
│   ├── 1.png
│   ├── 2.jpg
│   └── 3.gif
├── 3
│   ├── 1.zip
│   └── 2.mpeg
└── 4
    └── 1.mov

重要提示:请记住,这只是一个快速而肮脏的解决方案,不会检查 files/directoris 已经命名为“1”、“2”等

编辑:使用函数而不是递归调用同一脚本的更好方法。

希望我能得到所有极端情况。这递归地下降到目录以处理深度嵌套的目录树。

警告:由于脚本会注意不覆盖现有文件,因此在某些特殊情况下编号可能会出现空白——如果目录中有文件 0.txt 并且处理的是第一个文件该目录中有一个 .txt 文件,它将被移动到 1.txt。如果处理的第一个文件是 0.txt,也会发生这种情况,因此 运行 脚本两次将更改编号,然后 运行 再次将其改回。

代码如下:

#!/bin/bash

handle_directory() {
    local counter=0

    for i in *; do
        # if the file is a directory (but not a symlink),
        #  handle it before moving
        if [ -d  "$i" ] && ! [ -h "$i" ]; then
            cd "$i"
            handle_directory
            cd ..
        fi

        # extract suffix
        suffix="${i##*.}"

        if [ "$suffix" != "$i" ]; then
            extension=".$suffix"
        else
            # If there is no filename extension, the counter
            # is the whole filename. Without this, we'd get
            # 0.Makefile and suchlike.
            extension=""
        fi

        # find a filename that isn't already taken
        # this may lead to gaps in the numbering.
        while dest="$counter$extension" && [ -e "$dest" ]; do
            let ++counter
        done

        echo mv "$i" "$dest"
        let ++counter
    done
}

# if a parameter was given, go there to handle it.
# otherwise handle the local directory. 
if ! [ -z "" ] && ! cd ""; then
    echo "Could not chdir to directory "
    exit -1
fi

handle_directory

总体思路是对相关目录树进行深度优先搜索。像任何树一样,目录树最好递归处理,其功能本质上可以归结为:遍历该目录下的所有东西,如果是目录,则下降并处理它,然后找到合适的文件名并重命名该东西是否是不是目录。

用过的东西:

local counter=0 # declares a function-local variable counter and initializes it
                # to 0. crucially, that it is local means that every invocation
                # of handle_directory has its own counter.
[ -d "$i" ]     # tests if "$i" is a directory
[ -h "$i" ]     # tests if "$i" is a symlink
! [ ... ]       # negates the test. ! [ -h "$i" ] is true if "$i" is NOT a symlink
"${i##*.}"      # a bashism that cuts off the longest prefix that matches the pattern
[ -e "$dest" ]  # tests if "$dest" exists
              # the first parameter with which the script is called
[ -z "" ]     # tests if "" is an empty string
! cd ""       # descends into the directory "". true if that failed.

阅读联机帮助页以进一步理解:

man test
man bash # that's the big one.