使用: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つはリダイレクトです。
答え2
rsync_options を rsync コマンドで参照すると、これらすべてのオプションが個別のオプションではなく 1 つの引数として rsync に渡されます。したがって、rsyncは「-axhPv」フラグを使用してsshを実行しようとします。
デモンストレーション時間:
function showme () {
echo First: $1
echo Second: $2
echo Third: $3
}
$ showme "-e ssh -axhPv" two three
First: -e ssh -axhPv
Second: two
Third: three
$ showme -e ssh -axhPv two three
First: -e
Second: ssh
Third: -axhPv
答え3
-eパラメータ自体を引用符で囲む必要があると思います。
rsync -axhPv -e 'ssh -p 2222' user@host:/source_dir/ /dest_dir/
したがって、次のことを行う必要があります。
rsync_options="-e 'ssh' -axhPv"
二重引用符内で一重引用符をエスケープする必要がある場合や必要ない場合があります。