我正在构建一个脚本,该脚本应将当前用户主目录复制到任意选择的目录,并使用 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)?
答案1
转义的双引号被视为文件名的文字字符。既然您正在使用,bash
您可以使用它的数组来处理这个问题。
linkDest=()
[[ -n "$LAST_SNAPSHOT" ]] && linkDest+=('--link-dest' "$BACKUP_ROOT/$LAST_SNAPSHOT")
...
rsync $OPTS $EXCLUDES "${linkDest[@]}" "$MASTER/" "$NEW_SNAPSHOT"
"${linkDest[@]}"
如果引用为空,则引用将完全消失。否则它会扩展为其值的引用列表。如果$OPTS
和$EXCLUDES
也是列表,我会使用相同的机制。
答案2
问题是您已将双引号作为文件名的一部分。
使用数组来保存 的选项rsync
。
在/bin/sh
shell 中(也可以在 中工作bash
):
# options that are always set
set -- --archive --verbose
# add --link-dest=DIR if needed
if [ -n "$LAST_SNAPSHOT" ]; then
set -- "$@" --link-dest="$BACKUP_ROOT/$LAST_SNAPSHOT"
fi
# add some --excludes
set -- "$@" --exclude='*.ext' --exclude='dir/***'
# call rsync
rsync "$@" "$MASTER/" "$NEW_SNAPSHOT"
这利用了 POSIX shell 中唯一可用的数组(除非扩展、类似bash
等),即位置参数数组。通过设置此数组中的条目(使用set
)并根据需要添加到其中,我们可以确保rsync
正确处理带引号的参数(或任何命令)。在对 的调用中rsync
,我们使用"$@"
which 将确保数组中的条目单独用双引号括起来,从而防止 shell 进行分词和生成文件名。
等效的东西,但使用bash
数组:
# options that are always set
opts=( --archive --verbose )
# add --link-dest=DIR if needed
if [ -n "$LAST_SNAPSHOT" ]; then
opts+=( --link-dest="$BACKUP_ROOT/$LAST_SNAPSHOT" )
fi
# add some --excludes
opts+=( --exclude='*.ext' --exclude='dir/***' )
# call rsync
rsync "${opts[@]}" "$MASTER/" "$NEW_SNAPSHOT"
答案3
不同之处在于转义引号\"
会将其转换为字符串字符。
所以错误可能是正确的:
“/home/backuptest/dest/backuptest/20180619_134044”
名称中包含引号的部分与
/home/backuptest/dest/backuptest/20180619_134044
这就是您想要的解决此问题的推荐方法是使用 ${} 变量,例如:
$ 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