尝试在屏幕会话中将文件从一台服务器 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
-c
des"
为了更好地了解发生的情况,可以使用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