使用儲存在字元串中的 args 呼叫 rsync
這與我的 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執行您的腳本,因為它擅長發現此類常見問題。