【问题标题】:rsync run from bash script not preserving ownership从 bash 脚本运行的 rsync 不保留所有权
【发布时间】:2013-02-25 15:16:58
【问题描述】:

我正在尝试创建一个 bash 脚本,它将指定为命令行参数的目录同步到远程服务器(也由参数指定)。目前,我正在使用eval,它解决了参数扩展问题,但由于某种原因导致 rsync 无法保留远程文件的所有权(我知道除了是 Evil 之外)。从命令提示符运行带有所有相同标志和参数的 rsync 命令可以正常工作。

我尝试使用$() 作为替代方案,但我在变量扩展和保护远程 rsync 路径需要保护的位(需要引号 反斜杠带空格的路径)。

所以 - 我猜有两个问题 - eval 是否有理由阻止 rsync 保留所有权(bash 脚本在源计算机上以 root 身份运行,ssh 以root 太 - 只是现在)?有没有办法让$() 在这种情况下工作? (修剪后的)代码如下:

#!/bin/bash

RSYNC_CMD="/usr/bin/rsync"
RSYNC_FLAGS="-az --rsh=\"/usr/bin/ssh -i \${DST_KEY}\""  # Protect ${DST_KEY} until it is assigned later

SRC=${1}  # Normally this is sense checked and processed to be a canonical path

# Logic for setting DST based on command line parameter snipped for clarity - just directly assign for testing

DST='root@some.server.com:'
DST_KEY='/path/to/sshKey.rsa'

TARG=${DST}${SRC//' '/'\ '}  # Escape whitespace for target system

eval ${RSYNC_CMD} ${RSYNC_FLAGS} \"${SRC}\" \"${TARG}\"  # Put quotes round the paths - even though ${TARG} is already escaped

# All synced OK - but ownership not preserved despite -a flag

我尝试将RSYNC_CMD 更改为sudo /usr/bin/rsync,并将--rsync-path="sudo /usr/bin/rsync 添加到RSYNC_FLAGS,但都没有任何区别。我只是看不到我错过了什么......

【问题讨论】:

  • rsync --help | grep owner 告诉我:-o, --owner preserve owner (super-user only)。你试过那个选项吗?
  • 谢谢 - 正如@chepner 下面所说,-a 意味着 -o,如果我从命令行执行它,它工作正常,所以我假设它是 eval(只是为了确定,我确实尝试过-o,但没有区别)。我将在接下来的几天内尝试对 chepner 的重写。

标签: bash eval rsync


【解决方案1】:

正确的方法是使用数组。 -a 应该已经暗示了-o

RSYNC_CMD="/usr/bin/rsync"

DST='root@some.server.com:'
DST_KEY='/path/to/sshKey.rsa'

RSYNC_FLAGS=(-az --rsh="/usr/bin/ssh -i ${DST_KEY}")

SRC=${1}
TARG="${DST}$SRC"

${RSYNC_CMD} "${RSYNC_FLAGS[@]}" "${SRC}" "${TARG}"

使用RSYNC_RSH 而不是--rsh,您可以在设置变量值之前导出变量。这至少可以让您将导出放在设置其余标志的同一区域。然后您可以推迟完成它的值,直到您拥有正确的身份文件。

RSYNC_CMD="/usr/bin/rsync"
export RSYNC_RSH="/usr/bin/ssh -i %s"  # Use a placeholder for now; set it later
RSYNC_FLAGS=( -a -z )

# Later...

DST='root@some.server.com:'
DST_KEY='/path/to/sshKey.rsa'
RSYNC_RSH=$( printf "$RSYNC_RSH" "$DST_KEY" )


SRC=${1}
TARG="${DST}$SRC"

${RSYNC_CMD} "${RSYNC_FLAGS[@]}" "${SRC}" "${TARG}"

【讨论】:

  • 谢谢-我离开几天,所以不能直接尝试,但是在此期间,是否可以设置DST_KEY after RSYNC_FLAGS ,就像在我使用您的方法的原始代码中一样?我喜欢在顶部定义所有标志,但是这个需要包含计算出的DST_KEY - 然后eval 会根据需要进行扩展。
  • 我不建议使用eval,因为它可能存在安全风险。另一种选择是使用RSYNC_RSH 环境变量。它仍然需要在该过程的后期设置它的值,但我会用一个如何“干净”地这样做的例子来更新我的答案。
  • 更新有点丑。什么决定了DST_KEY 的值?可以在.ssh/config 中设置特定于站点的身份文件;那么你根本不需要-i 标志ssh
  • 这个想法是调用脚本并传递一个标识符(例如'dev'),脚本从中查找正确的主机名和 .rsa 文件。这样用户就不需要知道这些。我知道我可以在设置 DSTDST_KEY 之后设置 RSYNC_FLAGS - 但总的来说,我想知道是否有一种方法可以在不使用 eval 的情况下重新应用变量扩展。
  • 太棒了——效果很好,并且摆脱了许多烦人的\" 序列!我最后没有为RSYNC_FLAGS 使用数组——只是一个直字符串,但这似乎并不重要......我还得出结论,重复扩展是不可能的(基于其他 SO 帖子我读过),唯一的选择是eval。我想我很幸运 rsync 读取了那个特定的环境变量 :) 但我仍然无法弄清楚为什么使用 eval 的原始版本导致所有权保留失败......
猜你喜欢
  • 1970-01-01
  • 2012-06-22
  • 2014-03-28
  • 1970-01-01
  • 1970-01-01
  • 2022-01-20
  • 1970-01-01
  • 2012-12-15
  • 2017-11-04
相关资源
最近更新 更多