如何重命名备份文件,使用其备份版本作为文件名的后缀并使其不再隐藏

如何重命名备份文件,使用其备份版本作为文件名的后缀并使其不再隐藏

我一直在处理大量的图像文件。其中一部分是将分布在 1000 多个目录中的所有图像文件类型直接移动到一个目录中。有许多图片有完全相同的名称,但实际上是不同的图片。我使用以下一行代码来执行此操作:

find . -type f -exec mv --backup=t '{}' /media/DATA-HDD/AllImages \;

我这样做是为了使任何具有相同名称的图像都会生成一个隐藏的备份文件,而不是覆盖。它工作得很好,但现在我还有另一个问题需要解决。

现在,我当然有很多类似以下的瓷砖:

DSC_0616.NEF
DSC_0616.NEF.~1~
DSC_0616.NEF.~2~

我想要做的是运行一个命令(或脚本),它将通过在文件名中添加备份号作为后缀来重命名任何这些隐藏文件,并删除 .~[bu#]~ 以使它们成为唯一的文件名并且不隐藏。因此,就像这样:

DSC_0616.NEF
DSC_0616_1.NEF
DSC_0616_2.NEF

我花了好几个小时尝试研究并亲自尝试这一点,但却找不到任何在我知识范围内可以帮助我实现这一目标的东西。

答案1

只要您确定所有内容都按照上面描述的一致命名,一些正则表达式就可以通过 shell 脚本完成这项工作:

#!/bin/bash
# sets the file separator to be only newlines, in case files have spaces in them
IFS=$'\n'
for file in $(find . -type f); do
        # parses just the number(s) between two tildes, and only at the end of the file
        number=$(echo $file | grep -Eo "~[0-9]+~$" | sed s/'~'/''/g)
        # if no match found, assume this is a "base" file that does not need to be renamed
        if [ "$number" == "" ]; then
                continue
        fi
        # parses the file name through "NEF", then deletes ".NEF"
        filename=$(echo $file |  grep -Eio "^.+\.NEF" | sed s/'\.NEF'/''/g )
        if [ "$filename" == "" ]; then
                continue
        fi
        mv -v $file $(echo "$filename"_"$number.NEF")
        # if anything went wrong, exit immediately
        if [ "$?" != "0" ]; then
                echo "Unable to move file $file"
                exit 1
        fi
done

这也适用于目录降序排列,只需将脚本放置在项目目录树顶部的工作目录中并执行它即可。使用您提供的示例文件运行:

###@###:~/project$ find . -type f
./DSC_0616.NEF.~8~
./DSC_0616.NEF.~5~
./DSC_0616.NEF.~1~
./DSC_0616.NEF.~7~
./DSC_0616.NEF.~3~
./DSC_0616.NEF.~4~
./DSC_0616.NEF.~9~
./DSC_0616.NEF.~2~
./DSC_0616.NEF.~6~
./lower_dir/DSC_0616.NEF.~8~
./lower_dir/DSC_0616.NEF.~5~
./lower_dir/DSC_0616.NEF.~1~
./lower_dir/DSC_0616.NEF.~7~
./lower_dir/DSC_0616.NEF.~3~
./lower_dir/DSC_0616.NEF.~4~
./lower_dir/DSC_0616.NEF.~9~
./lower_dir/DSC_0616.NEF.~2~
./lower_dir/DSC_0616.NEF.~6~

运行脚本后:

###@###:~/project$ find . -type f
./DSC_0616_1.NEF
./DSC_0616_3.NEF
./DSC_0616_7.NEF
./DSC_0616_5.NEF
./DSC_0616_2.NEF
./DSC_0616_9.NEF
./DSC_0616_6.NEF
./DSC_0616_8.NEF
./DSC_0616_4.NEF
./lower_dir/DSC_0616_1.NEF
./lower_dir/DSC_0616_3.NEF
./lower_dir/DSC_0616_7.NEF
./lower_dir/DSC_0616_5.NEF
./lower_dir/DSC_0616_2.NEF
./lower_dir/DSC_0616_9.NEF
./lower_dir/DSC_0616_6.NEF
./lower_dir/DSC_0616_8.NEF
./lower_dir/DSC_0616_4.NEF

答案2

在评论中,OP 请求一个适用于任何扩展(不仅仅是 .NEF)的解决方案,而我也遇到了同样的问题。:p

与第一个答案相比,这里有一些更现代的 Bashism 的说法:

#!/usr/bin/env bash

# Renames the $1 directory's backup files (produced by `cp` or `mv` with the
# option `--backup=numbered`) such that "foo.png.~17~" becomes "foo_17.png"
function rename_backups()
{
    for THING in "${1}"/*
    do
        if [[ -f "${THING}" &&
              "${THING}" =~ ^.+\/+.+\..+~([0-9]+)~$ ]] # Take "foo.png.~17~".
        then
            # Get the "17".
            local BACKUP_NUMBER=${BASH_REMATCH[1]}

            # Remove the "~17~", leaving "foo.png".
            local SANS_BACKUP_NUMBER="${THING%.*}"

            # Get the filename, "foo", and the extension, "png".
            local FILENAME="${SANS_BACKUP_NUMBER%.*}"
            local EXT="${SANS_BACKUP_NUMBER##*.}"

            # Rename to "foo_17.png".
            local NEW_NAME="${FILENAME}_${BACKUP_NUMBER}.${EXT}"

            while [[ -f "${NEW_NAME}" ]]
            do
                # If "foo_17.png" already exists for some reason, keep
                # increasing the number until we find an unused one.
                ((++BACKUP_NUMBER))
                NEW_NAME="${FILENAME}_${BACKUP_NUMBER}.${EXT}"
            done

            mv --no-clobber "${THING}" "${NEW_NAME}"
        fi
    done
}

rename_backups your/backup/directory/here/

以下版本还支持无扩展文件:

#!/usr/bin/env bash

# Renames the $1 directory's backup files (produced by `cp` or `mv` with the
# option `--backup=numbered`) such that:
#     - "foo.png.~17~" becomes "foo_17.png"
#     - "bar.~17~" becomes "bar_17"
function rename_backups()
{
    for THING in "${1}"/*
    do
        # We'll either have a file like "foo.png.~17~" or "bar.~17~".
        if [[ -f "${THING}" && "${THING}" =~ ^.+~([0-9]+)~$ ]]
        then
            # Get the "17".
            local BACKUP_NUMBER=${BASH_REMATCH[1]}

            # Remove the "~17~", leaving, e.g., "foo.png".
            local SANS_BACKUP_NUMBER="${THING%.*}"

            # Get the filename, "foo", and the extension, "png".
            local FILENAME="${SANS_BACKUP_NUMBER%.*}"
            local EXT="${SANS_BACKUP_NUMBER##*.}"

            if [[ "${FILENAME}" == "${SANS_BACKUP_NUMBER}" ]]
            then
                # This is a "bar.~17~" case, so rename to "bar_17".
                local NEW_NAME="${FILENAME}_${BACKUP_NUMBER}"

                while [[ -f "${NEW_NAME}" ]]
                do
                    # If "bar_17" already exists for some reason, keep
                    # increasing the number until we find an unused one.
                    ((++BACKUP_NUMBER))
                    NEW_NAME="${FILENAME}_${BACKUP_NUMBER}"
                done
            else
                # This is a "foo.png.~17~" case, so rename to "foo_17.png".
                local NEW_NAME="${FILENAME}_${BACKUP_NUMBER}.${EXT}"

                while [[ -f "${NEW_NAME}" ]]
                do
                    ((++BACKUP_NUMBER))
                    NEW_NAME="${FILENAME}_${BACKUP_NUMBER}.${EXT}"
                done
            fi

            mv --no-clobber "${THING}" "${NEW_NAME}"
        fi
    done
}

rename_backups your/backup/directory/here/

相关内容