rsync narzeka na brakujące trailing- w skrypcie Bash

13

Próba synchronizacji plików między serwerami w sesji ekranowej. Zamiast pisać długie polecenie za każdym razem, zdecydowałem się na skrypt Bash. Jednak po uruchomieniu pojawia się Missing trailing-" in remote-shell command.błąd.

Zastanawiasz się, co się dzieje w skrypcie.

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]

Skrypt powtarza, co zrobi najpierw, a następnie wykona polecenie. Poniżej zrzut mojego skryptu:

#!/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
źródło

Odpowiedzi:

23

Krótka odpowiedź: patrz BashFAQ # 050 .

Długa odpowiedź: problemem jest to, że osadzanie cudzysłowów w zmiennych nie działa tak, jak myślisz. W szczególności cytaty są analizowane przed zastąpieniem zmiennych, więc jeśli wartość zmiennej zawiera cudzysłowy, jest za późno, aby działały poprawnie. Gdy ustawisz, RSYNCOPT="--rsh=\"ssh -p 10022 -c des\" ..."a następnie użyjesz ${RSYNCOPT}w wierszu poleceń, cudzysłowy w zmiennej nie są analizowane, są one traktowane jak zwykłe znaki. Tak więc, zamiast polecenia rsync otrzymania pojedynczego parametru --rsh=ssh -p 10022 -c des, otrzymuje 5: --rsh="ssh, -p, 10022, -ci des". Ponieważ polecenie --rsh zawiera pojedynczy (niedopasowany) cytat, pojawia się błąd.

Aby zobaczyć, co się dzieje lepiej, albo użyj set -xpolecenia, aby powłoka wypisała każde polecenie przed jego wykonaniem (aby zobaczyć, co się naprawdę dzieje), lub zamień na echo ${whatever}(co jest bardzo mylące) printf "%q " ${whatever}; echo.

Istnieje kilka sposobów rozwiązania tego problemu. Jednym z nich jest uniknięcie próby przechowywania RSYNCOPT(i prawdopodobnie również innych rzeczy) zmiennych w pierwszej kolejności. Innym jest przechowywanie RSYNCOPTjako tablica (która może śledzić granice słów bez żadnego zamieszania) zamiast zwykłego ciągu.

Aby wydrukować polecenie przed jego wykonaniem, użyj set -xprzed poleceniem rsync i ustaw + x po, aby je wyłączyć, lub użyj czegoś podobnego do printfpolecenia wymienionego powyżej (zwróć uwagę, że po poleceniu wypisuje ono zbłąkane miejsce, ale na ogół nie to ważne).

Oto podejście tablica + 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}
Gordon Davisson
źródło
Dzięki za wskazanie mi właściwego kierunku, w każdym razie szybkie spojrzenie na podany przez ciebie link przekonało mnie, że funkcja jest bardziej czytelna (a przynajmniej staje się taka, gdy jest odpowiednio sformatowana): 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} (Wiem, to jest dość stare, ale wciąż jedno pierwszych linków podczas wyszukiwania „Missing trailing-” w poleceniu powłoki zdalnej ”)
Francesco Marchetti-Stasi
6

Labirynt uciekających i nieskalowanych cudzysłowów w twoim $RSYNCOPTzamieszaniu do diabła ze mną; Nie dziwię się, że myli rsync i / lub ssh i / lub lokalną lub zdalną powłokę.

Może istnieć sposób, aby to uruchomić, dodając lub usuwając ukośniki odwrotne, ale zamiast tego sugeruję następujące obejście:

Zastąpić:

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

przez:

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

Wypróbowałem nieco uproszczoną wersję twojego skryptu w moim systemie i dostałem ten sam komunikat o błędzie, co ty; to obejście to poprawiło.

Keith Thompson
źródło