rsync se plaint de la "fin manquante" dans un script Bash

10

Essayer de rsynciser des fichiers d’un serveur à l’autre dans une session d’écran. Au lieu d'écrire la commande longue à chaque fois, j'ai décidé de mettre un script Bash. Cependant, quand je le lance, je reçois un Missing trailing-" in remote-shell command. Erreur.

Vous vous demandez ce qui ne va pas dans le script.

[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]

Le script fait écho à ce qu'il fera en premier, puis à l'exécution de la commande. Ci-dessous, un extrait de mon 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
la source

Réponses:

20

Réponse courte: voir BashFAQ # 050 .

Réponse longue: le problème que vous rencontrez est que l’incorporation de guillemets dans des variables ne fonctionne pas comme vous le pensez. Plus précisément, les citations sont analysées avant que les variables ne soient remplacées. Par conséquent, si la valeur d’une variable inclut des citations, il est trop tard pour qu’elles fonctionnent correctement. Lorsque vous définissez RSYNCOPT="--rsh=\"ssh -p 10022 -c des\" ..." et ensuite utiliser ${RSYNCOPT} dans une ligne de commande, les guillemets de la variable ne sont pas analysés, ils sont simplement traités comme des caractères normaux. Ainsi, plutôt que la commande rsync recevant un seul paramètre --rsh=ssh -p 10022 -c des, il en reçoit 5: --rsh="ssh, -p, 10022, -c, et des". Comme la commande --rsh contient une seule citation (sans correspondance), vous obtenez une erreur.

Pour voir ce qui se passe mieux, utilisez soit set -x pour que le shell imprime chaque commande avant de l’exécuter (pour que vous puissiez voir ce qui se passe réellement), ou remplacez la commande. echo ${whatever} (ce qui est très trompeur) avec printf "%q " ${whatever}; echo.

Il y a plusieurs façons de résoudre ce problème. On doit éviter d'essayer de stocker RSYNCOPT (et probablement aussi d'autres choses) dans les variables en premier lieu. Un autre est de stocker RSYNCOPT comme un tableau (qui peut garder une trace des limites de mots sans aucune de cette confusion) plutôt qu'une simple chaîne.

Pour imprimer la commande avant de l'exécuter, utilisez soit set -x avant la commande rsync et définissez + x après pour l'éteindre, ou utilisez quelque chose comme le printf La commande que j’ai énumérée ci-dessus (notez qu’elle imprime un espace perdu après la commande, mais cela n’a généralement aucune importance).

Voici l’approche 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
la source
6

Le labyrinthe de guillemets échappés et non échappés dans votre $RSYNCOPT confond le diable hors de moi; Je ne suis pas surpris que cela confonde rsync, et / ou ssh, et / ou le shell local ou distant.

Il peut y avoir un moyen de faire fonctionner cela en ajoutant ou en supprimant des barres obliques inverses, mais je suggère plutôt la solution de contournement suivante:

Remplacer:

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

par:

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

J'ai essayé une version légèrement simplifiée de votre script sur mon système et j'ai reçu le même message d'erreur que vous. cette solution de contournement l'a corrigé.

Keith Thompson
la source