Linux

使用儲存在字元串中的 args 呼叫 rsync

  • October 21, 2018

這與我的 mhddfs 執行緒中引用的腳本相同,我想根據一些輸入定義 args,然後呼叫 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 搞砸了,但我不知道如何正確呼叫它。任何的想法 ?

shell 在擴展變數之前解析引號,因此將引號放在變數的值中並不能達到您的預期——當它們到位時,它們做任何有用的事情都為時已晚。請參閱BashFAQ #50:我正在嘗試將命令放入變數中,但複雜的情況總是失敗!更多細節。

在這種情況下,您想要動態建構命令的參數列表,最好的選擇是將 arg 列表儲存在數組中。這樣,在創建數組時會解析引號,每個“單詞”都會儲存為單獨的數組元素,如果您正確引用變數,則數組元素會包含在命令的參數列表中,而不會進行任何不需要的解析:

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

注意所有的括號和+=賦值;和雙引號,大括號,以及[@]使用數組時,需要它才能正常工作。

順便說一句,您可能會注意到我使用了小寫的所有變數名。在 shell 中使用大寫變數名是危險的,因為其中有許多對 shell 和/或其他程序具有特殊含義,並且意外重用其中一個可能會產生意想不到的影響。事實上,$USER$HOST是這樣的(它們被初始化為目前的本地使用者名和主機名);重用它們可能不會造成麻煩,但最好通過使用小寫或混合大小寫的變數名來避免這個問題。但是您可能希望在腳本的開頭添加,因此如果未指定user=$USER,它將預設使用相同的使用者名。-u

此外,我在沒有它們的變數引用周圍添加了雙引號。沒有它們你通常可以僥倖逃脫,但使用它們來避免潛在問題是個好主意。我建議通過shellcheck.net執行您的腳本,因為它擅長發現此類常見問題。

引用自:https://serverfault.com/questions/936426