从bash脚本运行的rsync不保留所有权

从bash脚本运行的rsync不保留所有权,bash,eval,rsync,Bash,Eval,Rsync,我正在尝试创建一个bash脚本,它将指定为命令行参数的目录同步到远程服务器(也由参数指定)。目前,我正在使用eval,这解决了一个参数扩展问题,但由于某种原因导致rsync无法保留远程文件的所有权(我知道,除了邪恶之外)。在命令提示符下使用所有相同的标志和参数运行rsync命令可以正常工作 我尝试使用$()作为替代方法,但在变量扩展和保护远程rsync路径需要保护的位(带空格的路径需要引号和反斜杠)方面,我遇到了一个真正的麻烦 那么-我猜有两个问题-是否有原因eval阻止rsync保留所有权(b

我正在尝试创建一个bash脚本,它将指定为命令行参数的目录同步到远程服务器(也由参数指定)。目前,我正在使用
eval
,这解决了一个参数扩展问题,但由于某种原因导致rsync无法保留远程文件的所有权(我知道,除了邪恶之外)。在命令提示符下使用所有相同的标志和参数运行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\u CMD
更改为
sudo/usr/bin/RSYNC
,并添加了
--RSYNC路径=“sudo/usr/bin/rsync
rsync_标志
,但两者都没有任何区别。我只是看不出我缺少什么…

正确的方法是使用数组
-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\u 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}"

rsync--help | grep-owner
告诉我:
-o,--owner-preserve-owner(仅限超级用户)
。您尝试过这个选项吗?谢谢-正如@chepner在下面所说的,-a意味着-o,如果我从命令行执行,它工作得很好,所以我假设它是eval(只是为了确定,我尝试过-o,但没有区别)。在接下来的几天里,我将尝试chepner的重写。谢谢-我要离开几天,所以不能直接尝试,但在此期间,是否可以在
RSYNC_标志
之后设置
DST_键
,就像在我的原始代码中使用您的方法一样?我希望在顶部定义所有标志,但这一个需要包括计算的
DST_键
,然后根据需要扩展该键。我不建议使用
eval
,因为这可能会带来安全风险。另一个选项是使用
RSYNC\u RSH
环境变量。它仍然需要在以后的过程中设置它的值,但是我会用一个例子来更新我的答案,说明如何“干净地”进行更新。什么决定了DST_键的值?可以在
.ssh/config
中设置站点特定的标识文件;那么您就根本不需要
-i
标志来表示
ssh
。这样做的目的是调用脚本并传递一个标识符(例如“dev”),脚本从中查找正确的主机名和.rsa文件。这样用户就不需要知道这些。我知道我可以在设置
DST
DST\u键之后设置
RSYNC\u标志
——但总的来说,我想知道是否有一种方法可以在不使用eval.Great的情况下重新应用变量扩展,这非常有效,并且消除了许多恼人的
\“
序列!最后,我没有为
RSYNC\u标志使用数组-只是一个直字符串,但这似乎并不重要。。。我还得出结论,重复扩展是不可能的(根据我读过的其他SO帖子),唯一的选择是
eval
。我想我很幸运,
rsync
读取了特定的环境变量:),但我仍然无法理解为什么使用
eval
的原始版本导致所有权保留失败。。。