1 votes

Appeler rsync avec des arguments stockés dans une chaîne de caractères

Il s'agit du même script que celui cité dans mon fil de discussion sur les mhddfs, j'aimerais définir les args en fonction de certaines entrées, et appeler rasync par la suite. Je suis actuellement arrivé à ceci mais seul l'appel à rsync ne fonctionne pas :

#!/bin/bash

INCLUDE=""
EXCLUDE=""
USER=""
HOST=""
KEY=""
FORCE=false
SHUTDOWN=false
DESTINATION=""
LASTFULL=""

while getopts u:h:k:s:o:f:e:i: option
do
    case "${option}" in
        u) USER=${OPTARG};;
        i) INCLUDE=${OPTARG};;
        e) EXCLUDE=${OPTARG};;
        h) HOST=${OPTARG};;
        k) KEY=${OPTARG};;
        s) SHUTDOWN=true;;
        o) DESTINATION=${OPTARG};;
        f) FORCE=true;
    esac
done

if [ -z $USER ] || [ -z $HOST ] || [ -z $DESTINATION ]
then
    echo "Usage : $0 <-u : user> <-h : host> <-t : type> <-o : output directory> [-k : key] [-s : shutdown]"
    exit 1
fi

if [ ! -d "$DESTINATION/../Backup" ]
then
    if [ ! -d "$DESTINATION/Backup" ]
    then
        echo "Creating backup directory on target..."

        if ! mkdir "$DESTINATION/Backup"
        then
            echo "Could not create the backup directory. Exiting."
            exit 2
        fi
    fi
    DESTINATION="$DESTINATION/Backup"
fi

RSYNC_ARGS="-ravh -H --rsync-path=\"sudo rsync\" --append --progress --delete --safe-links"
if [ -f "$KEY" ]
then
    RSYNC_ARGS="$RSYNC_ARGS -e \"ssh -i $KEY\""
fi
if [ -f "$INCLUDE" ]
then
    echo "Including only files from $INCLUDE"
    RSYNC_ARGS="$RSYNC_ARGS --files-from=$INCLUDE"
fi
if [ -f "$EXCLUDE" ]
then
    echo "Excluding files from $EXCLUDE"
    RSYNC_ARGS="$RSYNC_ARGS --exclude-from=$EXCLUDE"
fi
if ! $FORCE
then
    LASTBACKUP=$(basename $(ls -td  $DESTINATION/*/ | sed "y/\t/\n/" | head -n 1 ) 2>/dev/null)
    echo "Processing backup based on --> $LASTBACKUP"
    RSYNC_ARGS="$RSYNC_ARGS --link-dest=../$LASTBACKUP"
else
    echo "Processing full backup"
fi

DESTINATION=$(echo "$DESTINATION/$(date '+%Y_%m_%d')" | sed "s#//#/#g")

rsync $RSYNC_ARGS $USER@$HOST:/ $DESTINATION 2> error.log

CODE=$?
if [ $CODE -eq 0 ]
then
    echo "Backup done : $DESTINATION"
    exit 0
else
    echo "Rsync stopped with code $CODE"
    exit $CODE
fi

J'obtiens

Rsync stopped with code 1

Le fichier error.log contient

Unexpected remote arg : <correct username>@<correct host>:/

Lorsque je fais un écho de l'appel rsync, que je le copie et le colle, cela fonctionne.

Je sais que $RSYNC_ARGS est à l'origine du problème, mais je ne sais pas comment l'appeler correctement. Une idée ?

2voto

nullDev Points 1778

Le Shell analyse les guillemets avant d'étendre les variables, donc mettre des guillemets dans la valeur d'une variable ne fait pas ce que vous attendez - le temps qu'ils soient en place, il est trop tard pour qu'ils fassent quoi que ce soit d'utile. Voir BashFAQ #50 : J'essaie de mettre une commande dans une variable, mais les cas complexes échouent toujours ! pour plus de détails.

Dans des cas comme celui-ci, où vous voulez construire dynamiquement la liste des arguments d'une commande, la meilleure option est de stocker la liste des arguments dans un tableau. De cette manière, les guillemets sont analysés lors de la création du tableau, chaque "mot" est stocké comme un élément distinct du tableau, et si vous référencez correctement la variable, les éléments du tableau sont inclus dans la liste d'arguments de la commande sans aucune analyse indésirable :

rsync_args=(-ravh -H --rsync-path="sudo rsync" --append --progress --delete --safe-links)
if [ -f "$key" ]
then
    rsync_args+=(-e "ssh -i $key")
fi
if [ -f "$include" ]
then
    echo "Including only files from $include"
    rsync_args+=(--files-from="$include")
fi
# ... etc
rsync "${rsync_args[@]}" "$user@$host:/" "$destination" 2> error.log

Notez que toutes les parenthèses et les += dans les affectations ; et les guillemets, accolades et [@] lors de l'utilisation du tableau, sont requis pour que cela fonctionne correctement.

Vous remarquerez que j'ai mis en minuscules tous les noms de variables. L'utilisation de noms de variables en majuscules dans le Shell est dangereuse, car un certain nombre d'entre elles ont une signification particulière pour le Shell et/ou d'autres programmes, et la réutilisation accidentelle de l'une d'entre elles peut avoir des effets inattendus. En fait, $USER y $HOST sont comme ceci (elles sont initialisées au nom d'utilisateur et au nom d'hôte locaux actuels) ; les réutiliser probablement ne posera pas de problème, mais il est préférable d'éviter le problème en utilisant des noms de variables en minuscules ou en majuscules mixtes. Mais vous pourriez vouloir ajouter user=$USER au début du script pour qu'il utilise par défaut le même nom d'utilisateur si -u n'est pas spécifié.

J'ai également ajouté des guillemets aux références des variables qui n'en avaient pas. Vous pouvez souvent vous en passer, mais c'est une bonne idée de les utiliser pour éviter des problèmes potentiels. Je recommande d'exécuter vos scripts par le biais de shellcheck.net car il est capable de repérer les problèmes courants de ce type.

0voto

crysman Points 482

Je n'ai pas pu poster avant que 40 minutes se soient écoulées depuis mon dernier message. Entre-temps, j'ai utilisé

eval rsync $RSYNC_ARGS $USER@$HOST:/ $DESTINATION 2> error.log

Ce qui fonctionne parfaitement.

SistemesEz.com

SystemesEZ est une communauté de sysadmins où vous pouvez résoudre vos problèmes et vos doutes. Vous pouvez consulter les questions des autres sysadmins, poser vos propres questions ou résoudre celles des autres.

Powered by:

X