返回

Shell 脚本中 Rsync 顺序执行的最佳实践

Linux

在 Shell 脚本中确保 Rsync 命令顺序执行的最佳实践

在进行文件同步时,rsync 是一个强大且常用的工具。通过网络高效地进行文件备份与同步。如果需要按顺序执行多个 rsync 命令,确保前一个命令执行完毕后再执行下一个命令,理解其背后的原理和使用正确的方法非常关键。场景设定在脚本中发起远端同步备份,有时一个同步命令传输大文件需要比较长的时间。在这种情况下,如果没有适当的控制机制,脚本可能会在前一个 rsync 进程结束之前就开始执行下一个命令。导致同步失败,或文件系统数据出错。

核心问题分析

脚本尝试通过 expect 脚本来自动化 rsync 的执行,包括远程认证的密码输入环节。用户输入密码被自动传送到 rsync 命令中。其中尝试使用 wait $! 的语法。问题在于 wait 命令在这种场景下的应用方式不正确。它更适合用在等待当前 shell 的后台作业,而不适合等待由 expect 脚本内部产生的后台作业。结果是后续命令可能会被提前执行。

解决方案详解

方案一:直接使用 Rsync 的阻塞模式

rsync 默认在当前进程下工作,即它是"阻塞"的。在一个 rsync 命令完全结束之前,脚本不会继续向下执行。这意味着可以直接把 rsync 写在 expect 中,完全不需使用 wait,利用它原本的同步行为执行,而不会变成后台工作。这才是符合设计初衷的工作模式。

操作步骤

  1. 在脚本中,移除wait $!

  2. 继续使用 expect,直接把rsync的命令和它的远程认证过程按顺序写入。确保 rsync 命令作为 expect 脚本中 spawn 命令的目标。

代码示例

HFDIR=/var/opt/ubkp/data/local/prework/hotfixes
RODIR=/var/opt/ubkp/data/local/prework/rollouts
THFDIR=$(ls -t /var/opt/ubkp/data/local | grep hotfix | head -1)
TRODIR=$(ls -t /var/opt/ubkp/data/local | grep rollout | grep -v check | head -1)
user=$(/usr/seos/bin/sewhoami)

if [ $user = "root" ]; then
    echo "This script should not be run as the TRUE root user"
    echo "Log in so that \"sewhoami\" does not display \"root\" and then execute this script."
    exit
else
    # list of ROs and HFs 
    list=/tmp/list.txt
    echo -n "Enter Password: "
    read -s PWD

    # 第一个 rsync 命令
    /usr/bin/expect<<EOD
spawn rsync -a $user@server:$HFDIR/* /var/opt/ubkp/data/local/$THFDIR
expect "assword"
send "$PWD\r" 
expect eof
EOD

    # 第二个 rsync 命令
    /usr/bin/expect<<EOD
spawn rsync -a $user@server:$RODIR/* /var/opt/ubkp/data/local/$TRODIR
expect "assword"
send "$PWD\r"
expect eof
EOD
fi

exit

expect脚本按照流程执行。顺序清晰且符合直觉。

安全建议

  • 虽然通过expect的脚本解决了密码的问题,在生产环境考虑使用SSH密钥对代替密码认证。避免密码硬编码或输入。提升系统安全性。

方案二:使用 && 连接多个 rsync 命令

&& 操作符是一个更符合传统操作习惯的选择。其确保前一个命令成功返回 (返回值为 0) 后再执行下一个命令。当处理比较小的脚本,以及调试同步过程非常方便。&&适用于在同一进程上下文中工作的多个命令。

操作步骤

  1. 可以将多个 rsync 命令通过 && 连接。
  2. 可以先尝试把所有认证替换成公钥。否则就要同时修改expect脚本把两行内容合起来。或者先执行一次 ssh-agent/ssh-add,再做后续无密同步操作也可以。

代码示例 :(假定已经设置SSH密钥对)

HFDIR=/var/opt/ubkp/data/local/prework/hotfixes
RODIR=/var/opt/ubkp/data/local/prework/rollouts
THFDIR=$(ls -t /var/opt/ubkp/data/local | grep hotfix | head -1)
TRODIR=$(ls -t /var/opt/ubkp/data/local | grep rollout | grep -v check | head -1)
user=$(/usr/seos/bin/sewhoami)

if [ $user = "root" ]; then
    echo "This script should not be run as the TRUE root user"
    echo "Log in so that \"sewhoami\" does not display \"root\" and then execute this script."
    exit
else
    # 第一个 rsync 命令
    rsync -a $user@server:$HFDIR/* /var/opt/ubkp/data/local/$THFDIR && \
    # 第二个 rsync 命令
    rsync -a $user@server:$RODIR/* /var/opt/ubkp/data/local/$TRODIR
fi

exit

通过一行写出所有rsync的内容简洁有效,并且保证所有执行逻辑都按照编写者规划好的流程执行。通过修改使整体认证部分符合最佳安全实践。

安全建议

  • 建议把认证环节单独拿出执行,统一规划。避免代码行过长不易理解。

总结:

不同的方案适合处理不同的使用场景。建议将rsyncexpect、SSH 无密认证三者搭配使用,完成更高级的系统同步和运维功能。按需进行错误处理,使系统整体可靠性显著提高。