是否可以仅使用rsync和posixshell脚本在中央服务器上同步多个客户端? 情景
我有一个文件服务器,作为要同步的文件的主存储,我有几个客户端,它们有主存储的本地副本。每个客户端都可以更改主存储器中的文件、添加新文件或删除现有文件。我希望通过定期执行同步操作,使它们尽可能保持同步,但我在任何地方都可以使用的唯一工具是是否可以仅使用rsync和posixshell脚本在中央服务器上同步多个客户端? 情景,shell,sh,posix,rsync,Shell,Sh,Posix,Rsync,我有一个文件服务器,作为要同步的文件的主存储,我有几个客户端,它们有主存储的本地副本。每个客户端都可以更改主存储器中的文件、添加新文件或删除现有文件。我希望通过定期执行同步操作,使它们尽可能保持同步,但我在任何地方都可以使用的唯一工具是rsync,我只能在客户端上运行脚本代码,不能在服务器上运行 问题 rsync不执行双向同步,因此我必须从服务器到客户端以及从客户端到服务器进行同步。对于刚通过运行两个rsync操作进行更改的文件,此操作可以正常工作,但在添加或删除文件时失败。如果我不使用带删除选
rsync
,我只能在客户端上运行脚本代码,不能在服务器上运行
问题
rsync
不执行双向同步,因此我必须从服务器到客户端以及从客户端到服务器进行同步。对于刚通过运行两个rsync
操作进行更改的文件,此操作可以正常工作,但在添加或删除文件时失败。如果我不使用带删除选项的rsync
,客户端将永远无法删除文件,因为从服务器到客户端的同步将恢复这些文件。如果使用删除选项,则首先运行从服务器到客户端的同步并删除客户端添加的所有新文件,或者首先运行从客户端到服务器的同步并删除其他客户端添加到服务器的所有新文件
问题
显然,
rsync
无法单独处理这种情况,因为只支持将一个位置与另一个位置同步。我当然需要编写一些代码,但我只能依赖POSIX shell脚本,这似乎使我无法实现目标。因此,甚至可以使用rsync来完成此操作吗?此场景所需的是三个同步操作,以及自上次同步以来本地客户端添加/删除了哪些文件。这种意识是必不可少的,它建立了一种状态,rsync
没有这种状态,因为rsync
是无状态的;当它运行时,它对以前或将来的操作一无所知。是的,它可以通过一些简单的POSIX脚本来完成
我们假设设置了三个变量:
metaDir
是一个目录,客户端可以在其中持久存储与同步操作相关的文件;内容本身未同步
localDir
是要同步的文件的本地副本
remoteStorage
是任何有效的rsync
源/目标(可以是挂载目录或rsync协议端点,带或不带SSH隧道)
filesAfterLastSync="$metaDir/files_after_last_sync.txt"
if [ ! -f "$metaDir/files_after_last_sync.txt" ]; then
rsync -a "$remoteStorage/" "$localDir"
( cd "$localDir" && find . ) | sed "s/^\.//" | sort > "$filesAfterLastSync"
exit 0
fi
为什么(cd“$localDir”和&find.)| sed“s/^\./”
?对于以后的rsync
,文件需要根目录为$localDir
。如果存在文件$localDir/test.txt
,则生成的输出文件行必须是/test.txt
,而不是其他文件。如果没有cd
和find
命令的绝对路径,它将包含/…abspath../test.txt
,如果没有sed
它将包含/test.txt
。为什么要显式调用sort
?再往下看
如果这不是我们的初始同步,我们应该创建一个临时目录,在脚本终止时自动删除自己,无论以何种方式:
tmpDir=$( mktemp -d )
trap 'rm -rf "$tmpDir"' EXIT
然后,我们创建一个文件列表,其中包含当前本地目录中的所有文件:
filesForThisSync="$tmpDir/files_for_this_sync.txt"
( cd "$localDir" && find . ) | sed "s/^\.//" | sort > "$filesForThisSync"
现在为什么会有sort
调用?原因是我需要在下面对文件列表进行排序。好的,那为什么不告诉find
对列表进行排序呢?这是因为find
不能保证排序与sort
相同(这在手册页上有明确说明),我需要的是sort
产生的顺序
现在我们需要创建两个特殊的文件列表,一个包含自上次同步以来添加的所有文件,另一个包含自上次同步以来删除的所有文件。仅使用POSIX这样做有点棘手,但存在各种可能性。以下是其中之一:
newFiles="$tmpDir/files_added_since_last_sync.txt"
join -t "" -v 2 "$filesAfterLastSync" "$filesForThisSync" > "$newFiles"
deletedFiles="$tmpDir/files_removed_since_last_sync.txt"
join -t "" -v 1 "$filesAfterLastSync" "$filesForThisSync" > "$deletedFiles"
通过将分隔符设置为空字符串,join
比较整行。通常,输出将包含两个文件中存在的所有行,但我们指示join仅输出其中一个文件中与另一个文件的行不匹配的行。仅存在于第二个文件中的行必须来自已添加的文件,且仅存在于第一个文件中的行必须来自已删除的文件。这就是我在上面使用sort
的原因,因为join
只能在按sort
对行进行排序的情况下才能正常工作
最后,我们执行三个同步操作。首先,我们将所有新文件同步到远程存储,以确保在开始执行删除操作时不会丢失这些文件:
rsync -aum --files-from="$newFiles" "$localDir/" "$remoteStorage"
什么是-aum
-a
表示存档,这意味着同步递归、保留符号链接、保留文件权限、保留所有时间戳、尝试保留所有权和组以及其他()-u
表示更新,这意味着如果目标中已存在文件,则仅当源文件具有较新的上次修改日期时才进行同步-m
表示删除空目录(如果不需要,可以将其删除)
接下来,我们将通过删除从远程存储同步到本地,以获得由其他客户端执行的所有更改和文件删除,但我们排除已在本地删除的文件,否则这些文件将恢复到我们不希望的状态:
rsync -aum --delete --exclude-from="$deletedFiles" "$remoteStorage/" "$localDir"
最后,我们通过删除从本地同步到远程存储,以更新本地更改的文件并删除本地删除的文件
rsync -aum --delete "$localDir/" "$remoteStorage"
有些人可能认为这太复杂了,只需两个sy就可以完成
( cd "$localDir" && find . ) | sed "s/^\.//" | sort > "$filesAfterLastSync"