バックアップスクリプトが失敗し、rsyncコマンドオプションが引用符で囲まれた変数にあります。

バックアップスクリプトが失敗し、rsyncコマンドオプションが引用符で囲まれた変数にあります。

使用:rsyncバージョン3.1.0プロトコルバージョン31(ベース:Ubuntu 14.04.3)

rsyncを使用するバックアップBashスクリプトの1つで、rsyncオプションを次の変数に入れました。

# Set rsync command options.

rsync_options="-e ssh -axhPv"

if [ "$deletion_type" = "DELETE_ON_DESTINATION" ]; then
    rsync_options="$rsync_options --delete"
fi

if [ "$run_type" = "DRY_RUN" ]; then
    rsync_options="$rsync_options --dry-run"
fi

# Run the backup.

rsync "$rsync_options" --log-file="$log_file" --exclude-from="$exclude_file" \
      "$source_dir" "$destination_dir"

エラーが表示されます。

unknown option -- h
usage: ssh [-1246AaCfgKkMNnqsTtVvXxYy] [-b bind_address] [-c cipher_spec]
           [-D [bind_address:]port] [-E log_file] [-e escape_char]
           [-F configfile] [-I pkcs11] [-i identity_file]
           [-L [bind_address:]port:host:hostport] [-l login_name] [-m mac_spec]
           [-O ctl_cmd] [-o option] [-p port]
           [-Q cipher | cipher-auth | mac | kex | key]
           [-R [bind_address:]port:host:hostport] [-S ctl_path] [-W host:port]
           [-w local_tun[:remote_tun]] [user@]hostname [command]
rsync: connection unexpectedly closed (0 bytes received so far) [sender]
rsync error: unexplained error (code 255) at io.c(226) [sender=3.1.0]

"$rsync_options"本能的には、Bashスクリプトから引用符を削除して再試行しました。

rsync $rsync_options --log-file="$log_file" --exclude-from="$exclude_file" \
      "$source_dir" "$destination_dir"

...この問題は解決され、素晴らしい動作します。

Bashスクリプトの変数にコマンドオプションを入れることは何度もやったことですが、特定の場合は思い出せませんが、たまに変数名の周りの二重引用符を削除しなければならなかった覚えがあります(今回以外は、確かに)。

私の質問は、引用符が問題を引き起こすのはなぜですか? rsyncまたはBashに関連する特定の問題が原因ですか?この問題を理解したいと思います。

ありがとうございます。

ベストアンサー1

オプションセットは、以下を使用して可視化できますprintf

$ printf '<%s>  '  "-e ssh -axhPv"  arg2  arg3 ; echo
<-e ssh -axhPv>  <arg2>  <arg3> 

引用符を削除すると、次の結果が表示されます。

$ printf '<%s>  '  -e ssh -axhPv  arg2  arg3 ; echo
<-e>  <ssh>  <-axhPv>  <arg2>  <arg3> 

つまり、引数はスペースで区切られ、コマンドに別々の要素として提供されます。

大量に

しかし、一般的な解決策は引用符を削除することではありません。これにより、各パラメーターがIFSパーティションとパス名拡張に公開されます。

正しい解決策は、値の配列を使用することです。

$ a=(-e ssh -axhPv  arg2  arg3)
$ printf '<%s>  ' "${a[@]}"; echo
<-e>  <ssh>  <-axhPv>  <arg2>  <arg3>   

これにより、スペースを含むオプションも追加できます。

$ a+=("arg with spaces" "one more")
$ printf '<%s>  ' "${a[@]}"; echo
<-e>  <ssh>  <-axhPv>  <arg2>  <arg3>  <arg with spaces>  <one more>  

したがって、コマンドに引数を提供する方法を制御できます。

スクリプトは以下を書き換えます。

#!/bin/bash
# Set rsync command options.
rsync_options=( "-e" "ssh" "-axhPv" )

if [ "$deletion_type" = "DELETE_ON_DESTINATION" ]; then
    rsync_options+=( "--delete" )
fi

if [ "$run_type" = "DRY_RUN" ]; then
    rsync_options+=("--dry-run")
fi

log_file="/var/tmp/log/script.sh"
exclude_file="/var/tmp/log/excludethis"
source_dir=/a
destination_dir=/b

# Run the backup.
    rsync_options+=('--log-file="'"$log_file"'"')
    rsync_options+=('--exclude-from="'"$exclude_file"'"')
    rsync_options+=("$source_dir")
    rsync_options+=("$destination_dir")
### Remove the printf to actually run the command:
printf '<%s>  ' rsync "${rsync_options[@]}"

注:配列に配置できないものの1つはリダイレクトです。

おすすめ記事