1

我有一个目录结构,其中目录和文件的名称不正确,我需要修复名称。目录有子目录,而这些子目录只有文件。

在这棵树中,我需要根据下表重命名文件和子目录。例如,一个名为的目录hdm应该重命名为hdu. hdm_e_01.png并且应根据hdu_e_01.png下面的转换表将名为的文件重命名为。

但是,请注意,这需要分两个阶段进行,因为已经有一个名为hdu那里的目录需要hds根据表重命名为,而且新重命名的目录hdu需要保持原样hdu而不是更改为hds. 因此,第一阶段需要将它们全部重命名为不冲突的临时名称,第二阶段需要重命名为最终名称。

From To
hda hdx
hde hdw
hdi hdv
hdm hdu
hdq hdt
hdu hds
hdb hdr
hdf hdq
hdj hdp
hdn hdo
hdr hdn
hdv hdm
hdc hdl
hdg hdk
hdk hdj
hdo hdi
hds hdh
hdw hdg
hdd hdf
hdh hde
hdl hdd
hdp hdc
hdt hdb
hdx hda
4

2 回答 2

1

首先,重命名您的目录:

cd /to/your/root/dir
cp -R hda /some/tmp/dir/hdx
cp -R hde /some/tmp/dir/hdw
cp -R hdi /some/tmp/dir/hdv
...

现在重命名您的文件:

cd /some/tmp/dir/ 
for d in "$(find . -type d -name 'hd*')" ; do
    cd "${d}"
    for f in *; do
        mv "${f}" "${d}${f:3}"
    done
    cd ..
done

基本上它会遍历您的目录,并根据目录名称根据您的规范重命名其中的文件,但它不检查从文件名开头删除的 3 个字符。

所以我建议echo在该行前面添加一个mv,例如:

        echo mv "${f}" "${d}${f:3}"

然后先查看输出。

如果您对结果满意,请执行重命名,然后删除原始目录并将修改后的目录移动到其位置。

然后有类似的解决方案mmv,但不是基本bash标准。

于 2013-09-12T08:26:10.740 回答
0

我感谢您提出的有趣问题。这是我的解决方案。

#!/bin/bash

TABLE_FILE='file.table'
DIRECTORY='.'
PRETEND=true  ## Set to false to change files.

declare -A RMAP=() FLAGS=() RENAMED=() NEWPATHS=()
declare -a ORDER=()

function check_directory {
    if [[ ! -d $DIRECTORY ]]; then
        echo "Directory does not exist: $DIRECTORY"
        return 1
    fi
    return 0
}

function parse_table_file {
    local -A F=() T=()
    local -i I=0

    if [[ ! -f $TABLE_FILE || ! -r $TABLE_FILE ]]; then
        echo "Table file does not exist or is not readable: $TABLE_FILE"
        return 1
    fi

    while read FROM TO; do
        if [[ -n ${F[FROM]} ]]; then
            echo "We can't have two the same sources: $FROM"
            return 1
        fi

        if [[ -n ${T[TO]} ]]; then
            echo "We can't have two them same replacements: $TO"
            return 1
        fi

        RMAP[$FROM]=$TO ORDER[I++]=$FROM F[$FROM]=. T[$TO]=.
    done < "$TABLE_FILE"
    return 0
}

function rename {
    local FROM=$1 TO=$2

    if [[ ${FLAGS[$FROM]} != R ]]; then
        if [[ ${FLAGS[$TO]} == H ]]; then
            echo "Circular rename point detected: $FROM - $TO"
            return 1
        elif [[ -n ${RMAP[$TO]} ]]; then
            FLAGS[$FROM]=H
            rename "$TO" "${RMAP[$TO]}" || return 1
        fi

        local -a TARGETS=("$DIRECTORY/$FROM"*)
        local NEWNAME NEWPATH

        for TARGET in "${TARGETS[@]}"; do
            NEWNAME=${TO}${TARGET##**"/${FROM}"}
            NEWPATH=${DIRECTORY}/${NEWNAME}

            echo "Renaming $TARGET to $NEWNAME ($NEWPATH)."

            if [[ -n ${NEWPATHS[$NEWPATH]} ]]; then
                echo "$TO has had same file matches as the previous ones: $NEWPATH through pattern ${NEWPATHS[$NEWPATH]}."
                return 1
            fi

            if [[ -e $NEWPATH ]]; then
                if [[ -n ${RENAMED[$NEWPATH]} ]]; then
                    if [[ $PRETEND == false ]]; then
                        echo "Can't rename $TARGET to $NEWNAME ($NEWPATH): file still exists and should have been renamed already with previous set ${RENAMED[$NEWPATH]}."
                        return 1
                    fi
                else
                    echo "Can't rename $TARGET to $NEWNAME ($NEWPATH): file already exists and is not part of the renaming sequence."
                    return 1
                fi
            fi

            if [[ $PRETEND == false ]]; then
                mv "$TARGET" "$NEWPATH" || {
                    echo "Failed to rename $NEWNAME to $NEWPATH."
                    return 1
                }
            fi

            NEWPATHS[$NEWPATH]=$TO
            RENAMED[$TARGET]="$FROM - $TO"
        done

        FLAGS[$FROM]=R
    fi

    return 0
}

function process {
    for FROM in "${ORDER[@]}"; do
        rename "$FROM" "${RMAP[$FROM]}" || return 1
    done
    return 0
}

check_directory && parse_table_file && process

该脚本利用递归来解决和检测冲突,而无需临时重命名。它还可以假装重命名,看看如果已经进行了更改,事情会发生什么,并防止错误。

示例我有这些文件:

aaa (D)
aab (D)
aaa.txt (F)

然后我的桌子上有这些行:

aaa aab
aab aac

这是我的输出:

Renaming ./aab to aac (./aac).
Renaming ./aaa to aab (./aab).
Renaming ./aaa.txt to aab.txt (./aab.txt).
于 2013-09-12T11:15:53.967 回答