Это тот же сценарий, что и приведенный в моем потоке mhddfs, я бы хотел определить аргументы в соответствии с некоторыми входными данными и впоследствии вызвать rasync. В настоящее время я придумал это, но не работает только вызов rsync:
#!/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
я получил
Rsync stopped with code 1
error.log содержит
Unexpected remote arg : <correct username>@<correct host>:/
Когда я повторяю вызов rsync, копирую и вставляю его, он работает
Я знаю, что $ RSYNC_ARGS все портит, но не знаю, как это правильно назвать. Любая идея ?
Оболочка анализирует кавычки перед раскрытием переменных, поэтому помещение кавычек в значение переменной не дает того, что вы ожидаете - к тому времени, когда они будут на месте, им уже слишком поздно делать что-нибудь полезное. Видеть BashFAQ # 50: Я пытаюсь поместить команду в переменную, но сложные случаи всегда терпят неудачу! Больше подробностей.
В таких случаях, когда вы хотите динамически создавать список аргументов команды, лучшим вариантом является сохранение списка аргументов в массиве. Таким образом, кавычки анализируются при создании массива, каждое «слово» сохраняется как отдельный элемент массива, и если вы правильно ссылаетесь на переменную, элементы массива включаются в список аргументов команды без какого-либо нежелательного анализа:
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
Обратите внимание, что все круглые скобки и +=
в заданиях; и двойные кавычки, фигурные скобки и [@]
при использовании массива обязательный чтобы это работало правильно.
Кстати, вы можете заметить, что я использовал все имена переменных в нижнем регистре. Использование имен переменных в верхнем регистре в оболочке опасно, потому что существует ряд из них, имеющих особое значение для оболочки и / или других программ, и случайное повторное использование одной из них может иметь непредвиденные последствия. По факту, $USER
и $HOST
такие (они инициализируются текущим локальным именем пользователя и именем хоста); повторно использовать их наверное не вызовет проблем, но лучше просто избежать проблемы, используя имена переменных в нижнем или смешанном регистре. Но вы можете добавить user=$USER
в начале скрипта, поэтому по умолчанию будет использоваться то же имя пользователя, если -u
не указано.
Кроме того, я заключил в двойные кавычки ссылки на переменные, у которых их не было. Вы часто можете обойтись без них, но лучше использовать их, чтобы избежать потенциальных проблем. Я рекомендую запустить ваши скрипты через shellcheck.net, так как он помогает выявлять такие типичные проблемы.
Я не мог публиковать сообщения, пока не прошло 40 минут с момента моего последнего сообщения. Тем временем я использовал
eval rsync $RSYNC_ARGS $USER@$HOST:/ $DESTINATION 2> error.log
Что отлично работает.