将文件从子目录移动到当前级别并重命名(如果存在)

将文件从子目录移动到当前级别并重命名(如果存在)

因为我在Mac上,所以mv有点不同,不支持该--backup属性,我能想到的最好的是

find . -mindepth 2 -type f -print -exec mv {} . \;     

答案1

您需要编写一些脚本。就像是:

find . -mindepth 2 -type f -print | while read x; do
    y=$(basename "$x")
    if [ -f "$y" ]; then
        mv "$y" "$y".backup
    fi
    mv "$x" "$y"
done

答案2

要创建命令目标的简单备份mv,除非它是目录:

if [ -e "$target" ] && [ ! -d "$target" ]; then
    mv "$target" "$target.backup"
fi

$target.backup如果是现有目录,这显然会产生不良后果。此外,我们会覆盖任何旧的($target.backup如果存在)。

使用枚举备份方案会更安全。

要创建命令目标的枚举备份mv,除非它是目录:

suffix=1
if [ -e "$target" ] && [ ! -d "$target" ]; then
    while [ -e "$target.$suffix" ]; do
        suffix=$(( suffix + 1 ))
    done

    mv "$target" "$target.$suffix"
fi

这将重命名$target$target.N使N文件名$target.N未使用的第一个正整数。

但请注意,这里存在一个竞争条件,即其他此代码的实例(或完全不相关的进程)可能会$target.$suffix在检测到该名称未使用并移动$target到该名称之间创建。

为了避免这种情况:

suffix=1
if [ -e "$target" ] && [ ! -d "$target" ]; then
    while [ -d "$target.$suffix" ] ||
          ! ln "$target" "$target.$suffix" 2>/dev/null; do
        suffix=$(( suffix + 1 ))
    done
fi

现在我们用来ln创建一个新名字(硬链接)对于$target.我们还跳过任何将生成现有目录名称的整数。在找到免费的新名称之前,此操作将会失败。

然后你可以做

mv "$source" "$target"

应用此命令来find移动所有常规文件,就像您所做的那样:

find . -mindepth 2 -type f -print -exec sh -c '
    for source do
        target=${source##*/}
        suffix=1

        if [ -e "$target" ] && [ ! -d "$target" ]; then
            while [ -d "$target.$suffix" ] ||
                  ! ln "$target" "$target.$suffix" 2>/dev/null; do
                suffix=$(( suffix + 1 ))
            done
        fi

        mv "$source" "$target"
    done' sh {} +

测试:

$ tree
.
|-- dir1
|   `-- file
|-- dir2
|   `-- file
`-- dir3
    `-- file

3 directories, 3 files
$ # the find command goes here
./dir1/file
./dir2/file
./dir3/file
$ tree
.
|-- dir1
|-- dir2
|-- dir3
|-- file
|-- file.1
`-- file.2

3 directories, 3 files

在此示例中,file将是最近找到的file文件、file.2之前找到的文件以及.file.1第一个找到的文件find


不幸的是,在 macOS 上的实现mv -n不会返回可用的退出状态。如果无法执行时返回非零mv,则可以使用更少的竞争条件以更简单的方式解决此问题。

答案3

这就是我最终的结果

num=1
find . -mindepth 2 -type f -print | while read x; do
    y=$(basename "$x")
    if [ -f "$y" ]; then
        mv "$y" "$y"."$num"
        num=$(( $num + 1 ))
    fi
    mv "$x" "$y"
done

因此,不要使用 .backup,如果有另一个相同的名称,它仍然可能发生。感谢您的灵感!

相关内容