rsync:使用变量时排除不起作用

rsync:使用变量时排除不起作用

有人能解释一下我最近通过 rsync 将目录同步到另一台服务器时注意到的这种行为吗?在这种情况下,我想排除子目录“done”。

当我将要与 rsync 一起使用的选项放入变量中时,该目录未被排除。但是当我将选项直接放在 rsync 调用后面时,该目录被排除。对“-av”的更改有所不同,但排除不起作用。

rsync 3.0.9-18,在 bash 上,CentOS 7.4

不排除:

$ RSYNC_OPTIONS='-av --exclude "done"'
$ touch done/test.ignore && rsync ${RSYNC_OPTIONS} ${SOURCEDIR} ${TARGET}
sending incremental file list
done/test.ignore

sent 132 bytes  received 32 bytes  109.33 bytes/sec
total size is 0  speedup is 0.00

不包括:

$ touch done/test.ignore && rsync -av --exclude "done" ${SOURCEDIR} ${TARGET}
sending incremental file list

sent 41 bytes  received 12 bytes  106.00 bytes/sec
total size is 0  speedup is 0.00

答案1

我复制了这个问题,并查看了set -x这两个命令的真实情况。结果发现这个命令

rsync ${RSYNC_OPTIONS} ${SOURCEDIR} ${TARGET}

实际上相当于

rsync -av --exclude '"done"' ${SOURCEDIR} ${TARGET}

注意引号中的引号。您的模式不是done;而是"done",就好像您要排除的目录在其实际名称中有双引号一样。


为了几乎修复这个问题,你可以在声明变量时不用这些麻烦的引号:

RSYNC_OPTIONS='-av --exclude done'                           # poor fix, don't
rsync ${RSYNC_OPTIONS} "${SOURCEDIR}" "${TARGET}"

但如果模式包含空格等,这将适得其反。另一种方法可能是eval

RSYNC_OPTIONS='-av --exclude "name  with  double  spaces"'
eval rsync "${RSYNC_OPTIONS}" '"${SOURCEDIR}" "${TARGET}"'   # not recommended

eval将第二次解析该行。正确安全地使用它非常困难。我使用双引号${RSYNC_OPTIONS},因此"name with double spaces"不会丢失双空格。我使用单引号"${SOURCEDIR}" "${TARGET}",因此这些变量不会立即扩展(否则它们的内容将进行扩展)。这很棘手!

此外,怎么样name "with' quotes?要将这个精确的字符串作为选项参数,rsync --exclude您需要在声明中使用一些模糊的引用和转义RSYNC_OPTIONS。还有更多理由避免eval


真正的解决方案是在 Bash 中使用数组。请注意,数组不可移植。

RSYNC_OPTIONS=(-av --exclude 'name with  spaces and $u(h')
rsync "${RSYNC_OPTIONS[@]}" "${SOURCEDIR}" "${TARGET}"

我理解为什么你没有${RSYNC_OPTIONS}在原来的方法中使用引号。但你应该${SOURCEDIR}分别引用和${TARGET}。上面的命令正确地引用了每个变量。

或者也许是${SOURCEDIR}为了指定多个来源?这可能是不引用它的原因,但它可能会带来与类似的问题${RSYNC_OPTIONS}。在这种情况下,您也应该在这里使用数组变量。

还请考虑变量名小写

答案2

那么像这样放置引文怎么样?

RSYNC_OPTIONS='-av --exclude '"done"''

我仅用简化的命令进行了测试:

SEP='-F ";"'
echo "1;2;3" | awk ${SEP} '{print $2}'

(不工作)

SEP='-F '";"''
echo "1;2;3" | awk ${SEP} '{print $2}'

(在职的)


编辑:

使用@Kamil 技术,数组也能很好地工作:

SEP=(-F ";")
echo "1;2;3" | awk ${SEP[@]} '{print $2}'

相关内容