Rsync 和引号

Rsync and quotes

我写了一个 bash 脚本,其中包含以下内容:

SRC="dist_serv:$HOME/www/"
DEST="$HOME/www/"
OPTIONS="--exclude 'file.php'"
rsync -Cavz --delete $OPTIONS $SRC $DEST

rsync 失败,我不知道为什么,尽管它似乎与 $OPTIONS 变量有关(当我删除它时它起作用)。我尝试使用反斜杠(以及许多其他内容)转义 space,但这没有用。 错误信息是:

rsync: mkdir "/home/xxx/~/public_html/" failed: No such file or directory (2)

我尝试引用变量,这引发了另一个错误("unknown option" 在我的变量 $OPTIONS 上):

rsync: --exclude 'xxx': unknown option
rsync error: syntax or usage error (code 1) at main.c(1422) [client=3.0.6]

在给变量赋值时,你不应该把 $ 放在变量名的前面。 SRC是一个变量,$SRC是它扩展到的值。

此外,当您将 ~ 放在引号中时,它不会扩展为您的主目录的路径。通常最好在脚本中使用 $HOME,因为此变量 的行为类似于变量 ,而 ~ 则不同。

总是引用变量扩展:

rsync -Cavz --delete "$OPTIONS" "$SRC" "$DEST"

除非有某些理由不这样做(很少有)。否则 shell 将对它们执行分词。

用户@Fred 指出你不能在 $OPTIONS 周围使用双引号(在下面的评论中),但如果你使用 OPTIONS='--exclude="file.php"' 应该没问题(注意 =).

我发现一种非常宝贵的技术是使用位置参数来简化选项列表的处理。

当您将选项放入变量(例如 OPTIONS 变量)时,您需要找到一种方法在值中包含引号,并在引用变量时省略引号。它有效,但你总是一个错字远离难以调试的失败。

改为尝试以下操作。

set -- -Cavz --delete
set -- "$@" --exclude "file.php"
set -- "$@" "dist_serv:~/www/"
set -- "$@" "~/www/"
rsync "$@"

当然,在这种情况下,一切都可以在同一行,但在许多情况下会有条件表达式,例如,您可以省略给定的选项,或 select 差异文件跟...共事。好消息是,您始终使用与在单个命令行中使用的引号相同的引号,这一切都归功于 "$@" 的魔力,它避免了引用(或引用)任何特定变量。

如果实际的位置参数妨碍您,您可以将它们放在变量中,或者创建一个函数来隔离上下文,避免在它们重要的地方触及它们。

我一直在使用这个技巧,并且由于引用导致我作为参数传递给命令的值内部出现问题,我已经不再拔头发了。

使用数组也可以得到类似的结果。

declare -a ARGUMENTS=()
ARGUMENTS=(-Cavz --delete )
ARGUMENTS+=(--exclude "file.php")
ARGUMENTS+=("dist_serv:~/www/")
ARGUMENTS+=("~/www/")
rsync "${ARGUMENTS[@]}"