rsync reclamando de `ausente trailing-" `em um script Bash

13

Tentando rsync arquivos de um servidor para outro em uma sessão de tela. Em vez de escrever o comando longo toda vez, decidi inserir um script Bash. No entanto, quando o executo, recebo um Missing trailing-" in remote-shell command.erro.

Pensando no que está errado no script.

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]

O script ecoa o que ele fará primeiro e depois executa o comando. Abaixo está um despejo do meu 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
fonte

Respostas:

23

Resposta curta: consulte BashFAQ # 050 .

Resposta longa: o problema que você está enfrentando é que a incorporação de aspas em variáveis ​​não funciona da maneira que você pensa. Especificamente, as aspas são analisadas antes que as variáveis ​​sejam substituídas; portanto, se o valor de uma variável incluir aspas, é tarde demais para que elas funcionem corretamente. Quando você define RSYNCOPT="--rsh=\"ssh -p 10022 -c des\" ..."e usa ${RSYNCOPT}em uma linha de comando, as aspas da variável não são analisadas, são tratadas apenas como caracteres normais. Assim, em vez do comando rsync receber um único parâmetro --rsh=ssh -p 10022 -c des, ele recebe 5: --rsh="ssh, -p, 10022, -c, e des". Como o comando --rsh contém uma única cotação (sem correspondência), você recebe um erro.

Para ver o que está acontecendo melhor, use set -xpara fazer com que o shell imprima cada comando antes de executá-lo (para que você possa ver o que realmente está acontecendo) ou substitua o echo ${whatever}(que é altamente enganador) por printf "%q " ${whatever}; echo.

Existem várias maneiras de resolver isso. Uma é evitar tentar armazenar RSYNCOPT(e provavelmente outras coisas também) variáveis ​​em primeiro lugar. Outra é armazenar RSYNCOPTcomo uma matriz (que pode acompanhar os limites das palavras sem nenhuma confusão), em vez de uma sequência simples.

Para imprimir o comando antes de executá-lo, use set -xantes do comando rsync e defina + x depois para desativá-lo ou use algo como o printfcomando que listei acima (observe que ele imprime um espaço perdido após o comando, mas isso geralmente não é possível). não importa).

Aqui está a abordagem 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
fonte
Obrigado por me apontar na direção certa, de qualquer maneira, uma rápida olhada no link que você forneceu me convenceu de que uma função é mais legível (ou pelo menos fica assim quando formatada corretamente): 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} (eu sei, isso é bastante antigo, mas ainda assim é um) dos primeiros links ao procurar por "Missing trailing-" no comando shell remoto ")
Francesco Marchetti-Stasi
6

O labirinto de aspas escapadas e não escapadas no seu $RSYNCOPTconfunde o inferno fora de mim; Não estou surpreso que isso confunda rsync e / ou ssh e / ou o shell local ou remoto.

Pode haver uma maneira de fazer isso funcionar adicionando ou removendo barras invertidas, mas sugiro a seguinte solução alternativa:

Substituir:

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

de:

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

Tentei uma versão ligeiramente simplificada do seu script no meu sistema e recebi a mesma mensagem de erro que você; essa solução alternativa a corrigiu.

Keith Thompson
fonte