我正在构建一个脚本,该脚本应将当前用户的主目录复制到任意选择的目录,并使用 rsync 链接到同一目录中最近创建的副本(如果有)。
该命令按以下方式构建和执行:
...
[ -z $LAST_SNAPSHOT ] && LINK_DEST="" || LINK_DEST="--link-dest \"$BACKUP_ROOT/$LAST_SNAPSHOT\""
...
/usr/bin/rsync $OPTS $EXCLUDES $LINK_DEST "$MASTER/" "$NEW_SNAPSHOT"
当我运行脚本 rsync 时出现以下错误:
--link-dest arg does not exist: "/home/backuptest/dest/backuptest/20180619_134044"
如果该目录实际上不存在但确实存在,则这是可以预期的。
如果我删除构建变量的代码中的引号,则$LINK_DEST
产生以下代码
[ -z $LAST_SNAPSHOT ] && LINK_DEST="" || LINK_DEST="--link-dest $BACKUP_ROOT/$LAST_SNAPSHOT"
然后 rsync 不会抱怨。我确实希望防止路径中的任何空格,所以我真的需要双引号。
我无法理解错误所在。是我如何调用 rsync 还是我以某种方式误解了 shell(bash)?
转义的双引号被视为文件名的文字字符。由于您正在使用
bash
,您可以使用它的数组来处理这个问题。如果引用
"${linkDest[@]}"
为空,则引用完全消失。否则,它会扩展为其值的引用列表。如果$OPTS
并且$EXCLUDES
也是列表,我会为这些列表使用相同的机制。问题是您已将双引号作为文件名的一部分。
使用数组将选项保存到
rsync
.在
/bin/sh
shell 中(也可以在 中工作bash
):这利用了 POSIX shell 中唯一可用的数组(除非扩展,like
bash
和其他),即位置参数数组。通过设置这个数组中的条目(使用set
)并根据需要添加到它,我们可以确保rsync
适当地处理引用的参数(或任何命令)。在对 的调用中rsync
,我们使用"$@"
which 将确保数组中的条目单独被双引号括起来,因此可以防止 shell 进行分词和文件名生成。等效的东西,但使用
bash
数组:不同之处在于转义引号
\"
会将其转换为字符串字符。所以错误可能是正确的:
其中包括引号是名称的一部分不同于
这就是您想要的解决此问题的推荐方法是使用 ${} 变量,例如:
$ myvar=var $ echo "\"$myvar\"" "var"
$ echo "${myvar}" var
所以像 "--link-dest "${BACKUP_ROOT}"/"${LAST_SNAPSHOT}"" 这样的东西应该让你更接近。
有关此的更多信息: https ://stackoverflow.com/questions/8748831/when-do-we-need-curly-braces-around-shell-variables 和 http://wiki.bash-hackers.org/syntax/pe #simple_usage