在动态 rsync 命令中转义双引号

在动态 rsync 命令中转义双引号

我正在构建一个脚本,该脚本应将当前用户主目录复制到任意选择的目录,并使用 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/shshell 中(也可以在 中工作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-variableshttp://wiki.bash-hackers.org/syntax/pe#simple_usage

相关内容