因为我在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,如果有另一个相同的名称,它仍然可能发生。感谢您的灵感!