递归移动(`mv -rn`,如`cp -rn`),仅移动不存在的文件的移动

递归移动(`mv -rn`,如`cp -rn`),仅移动不存在的文件的移动

语境

我有用户上传的内容需要备份。内容位于 3 个独立的服务器上/var/www/domain/media/(在每个服务器上都位于同一位置)。备份是安装在 的 NFS RAID /var/www/domain/bak/

media/与 属于不同的用户bak/,基本上 web 应用程序可以写入media/但只能读取bak/(用户只能删除其上传,直到在 00:00 GMT 备份为止)。

这导致了两个问题:用户可以强制使用相同的文件名覆盖备份中的文件,并且文件media/可能最终出现在两个不同的服务器上(如果用户上传两次并且由一个不同的服务器)。

所有这些都在 4 个 CenOS 7 上运行(Web X 3 + 备份 X 1)。 “Web”服务器的磁盘空间有限,需要将内容移动到备份服务器以防止它们填满磁盘。

没有竞争条件所以这是我们不需要关心的事情。备份是通过在ssh其他三台机器上顺序执行命令从单个备份机器完成的。


目前的解决方案

文件“移动”到备份是在清除重复项后完成的:

find /var/www/domain/media/ -type f | > media
find /var/www/domain/bak/ -type f | awk '{a=gensub("bak","media",1); print a}' > bak
cat bak media | sort | uniq -d > dupes
cat dupes | xargs rm
cp -r /var/www/domain/media/* /var/www/domain/bak/
rm -rf /var/www/domain/media/*

使用的问题mv/var/www/domain/media/每个用户都有子目录。例如:

media/user13/myvideo.webm
media/user13/walk-in-the-park.webm
media/user16/cat-video.webm
media/user17/presentation-may-2016.webm

bak/user13/mountai-trip.webm
bak/user13/walk-in-the-park.webm
bak/user14/reax-the-dog.webm

该命令必须为user16和创建目录user17,同时必须避免覆盖bak/user13/walk-in-the-park.webm


当前解决方案存在问题

我想保留重复项media/而不是删除它们。将它们复制到另一个地方也会遇到同样的问题,因为新文件会在白天出现,我需要将复制品与其副本同步。

我如何移动所有media/不存在的文件bak/,同时保留目录结构而不删除已存在的文件。

换句话说,我正在寻找一个能够执行以下操作的动作:

source      | destination         | action
----------- | ------------------- | ----------------------------------
file exists | file does not exist | move (`mv`), source -> destination
file exists | file exists         | do nothing, both files stay as they are
no file     | file exists         | do nothing (will not trigger)
no file     | file does not exist | do nothing (well, there's nothing to do something with!)

尝试更优雅的解决方案

我相信rsync一定能够做到这一点。我知道,--remove-source-files但我找不到办法不是检查时间戳、校验和、文件大小等等。

我将保存和检查校验和作为一个完全独立的过程。

我只关心文件名。我知道这可能会导致文件损坏,但我担心在普通磁盘上而不是在 RAID 服务器上获取损坏的文件要容易得多。

rsync欢迎非解决方案。我想编写一个shell脚本来执行移动(从目前的解决方案部分)。然而,一旦我想到这很容易出错,我就放弃了。

我也尝试过:

tar -cf /var/www/domain/media | (cd /var/www/domain/bar; tar -kxf -)

但它对于媒体文件(可能相当大)来说太慢,并且将所有文件保持在media/(磁盘空间有限)。

答案1

如果文件已存在于目标树中(无论任何元数据),若不执行任何操作,请将该选项传递--ignore-existing给 rsync。

rsync -a --remove-source-files --ignore-existing /var/www/domain/media/ /var/www/domain/bak/

为了完整起见,这是一个基于源和目标位于同一文件系统上的情况的解决方案(在这种情况下,find这不是一个好的解决方案,因为它复制然后删除文件,而不是简单地将它们移动到目标目录) 。mvrsync

cd /var/www/domain/media
find -type f -exec '
  for x; do
    if ! [ -e "/var/www/domain/bak/$x" ]; then
      mkdir -p "/var/www/domain/bak/${x%/*}" &&
      mv -- "$x" "/var/www/domain/bak/$x"
    fi
  done
' sh {} +

相关内容