rsync quejándose de 'falta de seguimiento- "` en un script Bash

13

Intentando sincronizar archivos de un servidor a otro en una sesión de pantalla. En lugar de escribir el comando largo cada vez, decidí poner un script Bash. Sin embargo, cuando lo ejecuto, aparece un Missing trailing-" in remote-shell command.error.

Preguntándose qué va mal en el guión.

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]

El script hace eco de lo que hará primero y luego ejecutó el comando. A continuación se muestra un volcado de mi script:

#!/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
fuente

Respuestas:

23

Respuesta corta: ver BashFAQ # 050 .

Respuesta larga: el problema que tienes es que incrustar comillas en variables no funciona de la manera que crees. Específicamente, las comillas se analizan antes de reemplazar las variables, por lo que si el valor de una variable incluye comillas, es demasiado tarde para que funcionen correctamente. Cuando configura RSYNCOPT="--rsh=\"ssh -p 10022 -c des\" ..."y luego usa ${RSYNCOPT}en una línea de comando, las comillas en la variable no se analizan, solo se tratan como caracteres normales. Así, más que el comando rsync recibir un único parámetro --rsh=ssh -p 10022 -c des, que recibe 5: --rsh="ssh, -p, 10022, -c, y des". Como el comando --rsh contiene una comilla simple (no coincidente), obtiene un error.

Para ver qué está pasando mejor, use set -xpara hacer que el shell imprima cada comando antes de ejecutarlo (para que pueda ver lo que realmente está sucediendo) o reemplace el echo ${whatever}(que es altamente engañoso) con printf "%q " ${whatever}; echo.

Hay varias formas de resolver esto. Una es evitar tratar de almacenar RSYNCOPT(y probablemente otras cosas también) en variables en primer lugar. Otra es almacenar RSYNCOPTcomo una matriz (que puede hacer un seguimiento de los límites de las palabras sin nada de esta confusión) en lugar de una simple cadena.

Para imprimir el comando antes de ejecutarlo, use set -xantes del comando rsync y configure + x después para desactivarlo, o use algo como el printfcomando que mencioné anteriormente (tenga en cuenta que imprime un espacio perdido después del comando, pero esto generalmente no funciona) t importa).

Aquí está el enfoque de 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}
Gordon Davisson
fuente
Gracias por señalarme en la dirección correcta, de todos modos, un vistazo rápido al enlace que proporcionó me convenció de que una función es más legible (o al menos lo es cuando está formateada correctamente): 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} (Lo sé, esto es bastante antiguo, pero sigue siendo uno de los primeros enlaces al buscar "Falta el final-" en el comando de shell remoto ")
Francesco Marchetti-Stasi
6

El laberinto de comillas escapadas y sin escape en tus $RSYNCOPTconfusiones me saca de quicio; No me sorprende que confunda rsync, y / o ssh, y / o el shell local o remoto.

Puede haber una manera de hacer que esto funcione agregando o eliminando barras diagonales inversas, pero sugiero la siguiente solución alternativa en su lugar:

Reemplazar:

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

por:

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

Probé una versión ligeramente simplificada de su script en mi sistema y obtuve el mismo mensaje de error que usted; esta solución lo corrigió.

Keith Thompson
fuente