rsync жалуется на "отсутствующий трейлинг-" `в скрипте Bash

13

Попытка rsync файлов с одного сервера на другой в сеансе экрана. Вместо того, чтобы писать длинную команду каждый раз, я решил добавить скрипт Bash. Однако, когда я запускаю его, я получаю сообщение Missing trailing-" in remote-shell command.об ошибке.

Хотите знать, что идет не так в сценарии.

root@127.0.0.1:~# /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 sys@192.168.1.15:/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}
HanSooloo
источник

Ответы:

23

Краткий ответ: см. BashFAQ # 050 .

Длинный ответ: проблема в том, что вложение кавычек в переменные работает не так, как вы думаете. В частности, кавычки анализируются до замены переменных, поэтому, если значение переменной включает в себя кавычки, уже слишком поздно для правильной работы. Когда вы устанавливаете RSYNCOPT="--rsh=\"ssh -p 10022 -c des\" ..."и затем используете ${RSYNCOPT}в командной строке, кавычки в переменной не анализируются, они просто обрабатываются как обычные символы. Таким образом, а не Rsync команда получает один параметр --rsh=ssh -p 10022 -c des, он получает 5: --rsh="ssh, -p, 10022, -c, и des". Поскольку команда --rsh содержит одинарную (несопоставимую) кавычку, вы получаете ошибку.

Чтобы увидеть, что происходит лучше, либо используйте, set -xчтобы оболочка печатала каждую команду перед ее выполнением (чтобы вы могли видеть, что происходит на самом деле), либо замените echo ${whatever}(что весьма вводит в заблуждение) на printf "%q " ${whatever}; echo.

Есть несколько способов решить эту проблему. Во-первых, избегать попыток хранить RSYNCOPT(и, возможно, и другие вещи) в переменных в первую очередь. Другой способ - хранить RSYNCOPTв виде массива (который может отслеживать границы слов без какой-либо путаницы), а не в виде простой строки.

Чтобы напечатать команду перед ее выполнением, либо используйте set -xперед командой rsync и установите + x после, чтобы отключить ее, либо используйте что-то похожее на printfкоманду, которую я перечислил выше (обратите внимание, что после команды она выводит пробелы, но обычно это не не имеет значения).

Вот подход массива + 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}
Гордон Дэвиссон
источник
Спасибо, что указали мне правильное направление, в любом случае быстрый взгляд на предоставленную вами ссылку убедил меня в том, что функция более читабельна (или, по крайней мере, она становится таковой при правильном форматировании): run_rsync() { /opt/bin/rsync "--rsh=\"ssh -p 10022 -c des\" --rsync-path=\"/opt/bin/rsync\" --inplace --progress -a -vv" $1 $2 } run_rsync ${SOURCE} ${REMOTE_USER}${REMOTE_HOST}${REMOTE_BASE}${REMOTE_TARGET} (Я знаю, это довольно старая, но все еще одна первых ссылок при поиске «Missing trailing-» в команде remote-shell »)
Франческо Маркетти-Штази
6

Лабиринт сбежавших и неиспользованных кавычек в твоих $RSYNCOPTруках сбивает меня с толку; Я не удивлен, что это сбивает с толку rsync, и / или ssh, и / или локальную или удаленную оболочку.

Может быть способ заставить это работать, добавляя или удаляя обратную косую черту, но я предлагаю вместо этого следующий обходной путь:

Заменить:

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"

Я попробовал немного упрощенную версию вашего скрипта в моей системе и получил то же сообщение об ошибке, что и вы; этот обходной путь исправил это.

Кит Томпсон
источник
1

Использование файла конфигурации ssh также допустимо. Вот что вы можете добавить / добавить в свой ~/.ssh/configфайл:

Port 10022
Cipher des

Вы также можете отфильтровать эти параметры по удаленному хосту , добавив эти строки Host xyz.domain.whateverи сделав для них отступ:

Host 192.168.1.15
    Port 10022
    Cipher des
Бенуа Даффез
источник