update2:我很无聊,但我会解释第二个解决方案。

update2:我很无聊,但我会解释第二个解决方案。

我想将文件夹 A 同步到文件夹 B,但有以下限制

  • 文件夹 A 包含数百个文件夹中的数千个文件以及数百 GB 的文件。

  • 文件夹 B 将包含文件夹 A 中最新的 10GB(或其他)文件(以及所有必需的文件夹),以复制文件夹 A 中最新文件的文件和结构。

  • 每次运行同步时,文件夹 B 将仅限于文件夹 A 中最新的 10GB 文件,旧文件将被丢弃。

  • 空目录应该被修剪,但如果需要的话我可以自己修剪。

如果有更好的工具可以在 bash 或 OS X 下运行,我不一定愿意通过 rsync 来执行此操作,但它需要能够独立运行并且无需登录会话。

答案1

#如果被否决,请在评论中解释原因。真糟糕!

从我的评论中我找到了一个解决方案:

整个命令行是这样的: $ find . -type f -printf "%T@ %p %s\n"| sort -n -r | awk '{ i+=$3; if (i<=200000) {print $2}}' | tar -cvf toto.tar -T -&& ssh -n prd "rm -rf dir/*" && scp toto.tar prd:tmp/ && ssh -n prd "tar xvf tmp/toto.tar"

该命令以 find 开头,查找当前目录中的所有文件(应适应服务器 A 上的目录路径)并打印 3 个字段

  • %T@ 打印unix时间戳
  • find%p 打印启动时的文件路径
  • %s 打印文件的大小(以字节为单位)
  • \n 当然是新行。

然后对输出find进行排序sort -n -r,对第一个字段进行数字反向排序,将 unix 时间戳从最近到最旧进行排序。

为了处理大小限制,awk可以通过打印输出的第二个字段来提供一点帮助sort,直到大小总和低于限制。对于它处理的每一行,它将第三个字段(大小)的值求和到局部变量i,然后打印排序输出的第二个字段(如果i低于限制)。

tar -cvf toto.tar -T -将根据awk输出提供的文件列表构建一个名为 toto.tar 的存档。

如果成功,首先删除服务器B的备份;然后scp toto.tar host:dir将文件传输到远程服务器(服务器B),然后ssh -n "tar xvf dir/toto.tar将传输的存档解压到保留目录结构的远程文件夹上。

我之前基于 scp 的解决方案没有保留目录结构,这就是我编辑这个答案的原因。

这是在我的 homedir 中运行的结果,最大大小为 200kb:

$ rm toto.tar; find . -type f -printf "%T@ %p %s\n"| sort -n -r | awk '{ i+=$3; if (i<=200000) {print $2}}'  | tar -cvf toto.tar -T -&& scp toto.tar prd:tmp/ && ssh -n prd "tar xvf tmp/toto.tar"
./.lesshst
./.viminfo
./scpplus
./.config/xfce4/desktop/icons.screen0-1350x650.rc
./.xsession-errors
./.config/xfce4/xfconf/xfce-perchannel-xml/xfce4-panel.xml
./.config/pulse/7f14833c645d4a6abb0beba68b79e0c0-default-source
./.config/pulse/7f14833c645d4a6abb0beba68b79e0c0-default-sink
./.cache/imsettings/log
./.cache/gpg-agent-info
./.ICEauthority
./.vboxclient-draganddrop.pid
./.vboxclient-seamless.pid
./.vboxclient-display.pid
./.vboxclient-clipboard.pid
./.dbus/session-bus/7f14833c645d4a6abb0beba68b79e0c0-0
./.cache/xscreensaver/xscreensaver-getimage.cache
./.config/xfce4/desktop/icons.screen0-1264x950.rc
./work/fpart-0.9.2/src/fpart
toto.tar                                                                                                                              100%  170KB 170.0KB/s   00:00    
./.lesshst
./.viminfo
./scpplus
./.config/xfce4/desktop/icons.screen0-1350x650.rc
./.xsession-errors
./.config/xfce4/xfconf/xfce-perchannel-xml/xfce4-panel.xml
./.config/pulse/7f14833c645d4a6abb0beba68b79e0c0-default-source
./.config/pulse/7f14833c645d4a6abb0beba68b79e0c0-default-sink
./.cache/imsettings/log
./.cache/gpg-agent-info
./.ICEauthority
./.vboxclient-draganddrop.pid
./.vboxclient-seamless.pid
./.vboxclient-display.pid
./.vboxclient-clipboard.pid
./.dbus/session-bus/7f14833c645d4a6abb0beba68b79e0c0-0
./.cache/xscreensaver/xscreensaver-getimage.cache
./.config/xfce4/desktop/icons.screen0-1264x950.rc
./work/fpart-0.9.2/src/fpart

主要问题是该解决方案在从主服务器传输最新 10gig 数据之前删除了备份文件夹。如果最新数据集和备份数据集有很多共同的文件/目录,效率就不是很高。但这是真正追踪最新 10gig(或其他)最新数据的非常简单的方法,无论数据是什么(快速且肮脏)

update2:我很无聊,但我会解释第二个解决方案。

我终于找到了第二个解决方案,我现在将对此进行解释。它的编码效率不高,它是一个大型在线程序,可以格式化为 shell 脚本,并在失败或文件名格式奇怪的情况下进行基本检查。

第一个解决方案的最大问题是它总是尝试备份最后 10gig 的最新文件。已经备份的内容。这意味着如果新启动时只有 100M 新文件,它将擦除整个备份并再次传输 10G 数据(最新 100M,新少 9.9G)

这是单行: ssh -n prd 'cd /var/tmp/test/ && find . -type f -printf "%T@ %p %s\n" ' |awk '{ print int($1)" "$2" "$3 }'|sort -n -r >/tmp/remote ; find . -type f -printf "%T@ %p %s\n" |awk '{ print int($1)" "$2" "$3 }'|sort -n -r | awk '{ i+=$3; if (i<=200000) {print $1" "$2" "$3}}'>/tmp/locale; grep -F -x -v -f /tmp/remote /tmp/locale |cut -d" " -f2 >/tmp/newfile;grep -F -x -v -f /tmp/locale /tmp/remote |cut -d" " -f2 >/tmp/toremove; cat /tmp/toremove |while read i; do echo "removing $i on remote server"; ssh -n prd "rm /var/tmp/test/$i"; done ; cat /tmp/newfile | tar -cvf toto.tar -T -&& scp toto.tar prd:/var/tmp/test/ && ssh -n prd "cd /var/tmp/test; tar xvf /var/tmp/test/toto.tar; rm /var/tmp/test/toto.tar"; rm /tmp/remote /tmp/locale /tmp/toremove /tmp/newfile toto.tar

当然,prd您的服务器 B 以及本地/远程服务器上的所有目录路径(创建临时文件除外)都会更改。请注意,不要处理内部带有空格或特殊字符的文件名。

解释:

主要思想是了解哪些是备份服务器上未备份的最新文件。擦除备份服务器上太旧的文件,并仅向其传输不存在的最新文件,所有这些都请记住大小限制。

  • 首先连接到备份服务器并获取备份文件列表:ssh -n prd 'cd /var/tmp/test/ && find . -type f -printf "%T@ %p %s\n" ' |awk '{ print int($1)" "$2" "$3 }'|sort -n -r >/tmp/remote ;;由于某些问题,我必须删除部分时间的小数部分,该问题tar始终将小数部分设置为0。这意味着备份服务器和源服务器之间的日期在小数部分上会有所不同。排序将从第一个字段的最大值到最低值进行排序,这意味着从最新的文件到最旧的文件。我将结果保存到/tmp/remote文件中。无需检查整个大小,因为我在之前的备份中传输的数据总是少于 10G。
  • 其次,我在本地执行相同的操作以获取总大小低于限制的最新文件的列表:find . -type f -printf "%T@ %p %s\n" |awk '{ print int($1)" "$2" "$3 }'|sort -n -r | awk '{ i+=$3; if (i<=200000) {print $1" "$2" "$3}}'>/tmp/locale;;我将结果保存到/tmp/locale

所以实际上所有在/tmp/locale和不在的文件/tmp/remote都是备份服务器上要同步的最新文件。所有在其中和不在其中的
文件都是备份服务器上要删除的文件(太旧)。/tmp/remote/tmp/locale

为了区分这些子集,我使用grep

  • grep -F -x -v -f /tmp/remote /tmp/locale |cut -d" " -f2>/tmp/newfile;将显示我保存到的 所有包含/tmp/locale和不包含的 文件/tmp/remote/tmp/newfile
  • grep -F -x -v -f /tmp/locale /tmp/remote |cut -d" " -f2 >/tmp/toremove;将显示包含/tmp/remote和不包含的所有文件/tmp/locale,我将其保存到/tmp/toremove

所以现在,我有了要远程删除的文件列表,以及要传输到备份服务器的文件列表,并保留目录结构。

我将使用tar构建区域设置存档来发送备份、远程删除旧文件、传输存档并解压它。

然后我们就快完成了。我删除临时文件/tmp进行清理。

详细信息如下: cat /tmp/toremove |while read i; do echo "removing $i on remote server"; ssh -n prd "rm /var/tmp/test/$i"; done ; 这个循环读取文件列表 i作为输入,显示一条小消息告诉我它删除了哪个文件并通过cat启动远程rmssh

cat /tmp/newfile | tar -cvf toto.tar -T -&& scp toto.tar prd:/var/tmp/test/ && ssh -n prd "cd /var/tmp/test; tar xvf /var/tmp/test/toto.tar; rm /var/tmp/test/toto.tar";将构建语言环境toto.tar存档,其中包含 中列出的所有文件/tmp/newfile。如果成功,我将其传输到远程服务器,然后通过远程解压它ssh,我也会删除备份服务器上的存档,这样就不会干扰下次启动。

rm /tmp/remote /tmp/locale /tmp/toremove /tmp/newfile toto.tar是本次启动期间使用的文件的本地清理。

这个在线程序可以被缩短,删除临时文件的使用,并将输出直接通过管道传输grepwhile循环和tar命令中。

它还可以改进以处理所有命令返回状态(没有足够的位置来构建存档;scpssh错误......)和奇怪的文件名(带有空格或特殊字符,以避免参数扩展混乱)

答案2

我最近有类似的问题。我最终得到的是 find + rsync。

#!/usr/bin/env bash
# first prepare the file list I want to sync

find /path -mtime 7 -other-conditions-you-want > /tmp/file.list.$$
rsync --file-from=/tmp/file.list.$$ /source /dest

当然,如果文件位于远程服务器上,您必须远程运行 find 并使用 --file-from=:/tmp/file.list.$$ 从远程获取文件列表,如下所示:

ssh "$_SOURCE_HOST" "cd '$_SOURCE_PATH'; find . $MMIN_FLAG -type f > /tmp/$_NAME-$TOKEN"
rsync "--files-from=:/tmp/$_NAME-$TOKEN" "$_SOURCE" "$_DEST"    
ssh "$_SOURCE_HOST" "rm -f /tmp/$_NAME-$TOKEN"

您可以像在 bash 中一样设置rm命令trap,以确保最后删除该文件。

相关内容