rsync 抱怨 Bash 脚本中缺少“尾随-”

rsync 抱怨 Bash 脚本中缺少“尾随-”

尝试在屏幕会话中将文件从一台服务器 rsync 到另一台服务器。我决定使用 Bash 脚本,而不是每次都输入长命令。但是,当我运行它时,出现了错误Missing trailing-" in remote-shell command.

想知道脚本中出了什么问题。

[email protected]:~# /raid/data/module/bin/rbk.sh Movies /raid/data/Movies rsync_target/

/raid/data/module/bin/screen -S Movies 

/opt/bin/rsync --rsh="ssh -p 10022 -c des"\
--rsync-path="/opt/bin/rsync" --inplace --progress -a -vv \
/raid/data/Movies [email protected]:/raid/data/rsync_target/

Missing trailing-" in remote-shell command.
rsync error: syntax or usage error (code 1) at main.c(361) [sender=3.0.5]

该脚本首先回显它将要执行的操作,然后执行命令。下面是我的脚本的转储:

#!/bin/bash
SCREEN="/raid/data/module/bin/screen"
SCREENOPT="-S"
SCREEN_TITLE=$1

RSYNC="/opt/bin/rsync"
RSYNCOPT="--rsh=\"ssh -p 10022 -c des\" --rsync-path=\"/opt/bin/rsync\" --inplace --progress -a -vv"

SOURCE=$2

REMOTE_USER="sys@"
REMOTE_HOST="192.168.1.15"
REMOTE_BASE=":/raid/data/"
REMOTE_TARGET=$3

echo ${SCREEN} ${SCREENOPT} ${SCREEN_TITLE}

echo ${RSYNC} ${RSYNCOPT} ${SOURCE} ${REMOTE_USER}${REMOTE_HOST}${REMOTE_BASE}${REMOTE_TARGET}
${RSYNC} ${RSYNCOPT} ${SOURCE} ${REMOTE_USER}${REMOTE_HOST}${REMOTE_BASE}${REMOTE_TARGET}

答案1

简短回答:参见Bash常见问题解答 #050

长答案:您遇到的问题是,在变量中嵌入引号并不像您想象的那样工作。具体来说,引号是在替换变量之前解析的,因此如果变量的值包含引号,它们就无法正常工作了。当您在命令行中设置RSYNCOPT="--rsh=\"ssh -p 10022 -c des\" ..."然后使用${RSYNCOPT}时,变量中的引号不会被解析,它们只会被视为普通字符。因此,rsync 命令不是接收单个参数--rsh=ssh -p 10022 -c des,而是接收 5 个参数:--rsh="ssh、、、和。由于 --rsh 命令包含单个(不匹配的)引号,-p因此您会收到错误。10022-cdes"

为了更好地了解发生的情况,可以使用set -x让 shell 在执行每个命令之前打印它(这样您就可以看到实际发生的情况),或者将echo ${whatever}(极具误导性)替换为printf "%q " ${whatever}; echo

有几种方法可以解决这个问题。一种方法是RSYNCOPT首先避免尝试将数据(可能还有其他东西)存储在变量中。另一种方法是将其存储RSYNCOPT为数组(可以跟踪单词边界而不会产生任何混淆),而不是简单的字符串。

要在执行命令之前打印该命令,请set -x在 rsync 命令之前使用并在之后设置 +x 将其关闭,或者使用类似printf我上面列出的命令(请注意,它会在命令后打印一个杂散空格,但这通常无关紧要)。

这是 array+printf 方法:

...
RSYNCOPT=(--rsh="ssh -p 10022 -c des" --rsync-path=\"/opt/bin/rsync\" --inplace --progress -a -vv)
...
printf "%q " ${SCREEN} ${SCREENOPT} ${SCREEN_TITLE}
echo

printf "%q " ${RSYNC} "${RSYNCOPT[@]}" ${SOURCE} ${REMOTE_USER}${REMOTE_HOST}${REMOTE_BASE}${REMOTE_TARGET}
echo
${RSYNC} "${RSYNCOPT[@]}" ${SOURCE} ${REMOTE_USER}${REMOTE_HOST}${REMOTE_BASE}${REMOTE_TARGET}

答案2

你文件中转义和非转义引号的迷宫$RSYNCOPT让我很困惑;我对它混淆 rsync、ssh、和/或本地或远程 shell 并不感到惊讶。

可能有一种方法可以通过添加或删除反斜杠来实现这​​一点,但我建议采用以下解决方法:

代替:

RSYNCOPT="--rsh=\"ssh -p 10022 -c des\" --rsync-path=\"/opt/bin/rsync\" --inplace --progress -a -vv"

经过:

export RSYNC_RSH="ssh -p 10022 -c des"
RSYNCOPT="--rsync-path=\"/opt/bin/rsync\" --inplace --progress -a -vv"

我在我的系统上尝试了稍微简化的脚本版本,并得到了与您相同的错误消息;这个解决方法纠正了它。

答案3

使用ssh 配置文件也是一个有效的选项。以下是您可以放入/添加到~/.ssh/config文件中的内容:

Port 10022
Cipher des

你也可以通过远程主机过滤这些参数在这些行前面添加Host xyz.domain.whatever并缩进:

Host 192.168.1.15
    Port 10022
    Cipher des

相关内容