MacOS の rsync スクリプトの環境変数のスペースに関する問題

MacOS の rsync スクリプトの環境変数のスペースに関する問題

毎日のバックアップ用に実行する予定の Bash スクリプトがあります (私の HOME は /Volumes/Norman Data/me です)。

#!/bin/bash

# Halt the script on any errors.
set -e

# Remote server where
remote_server="example.com"

# Destination Folder on Remote Server
target_path="backup/"

# User (with sshy key) on remote server
usr="me"


# ${HOME} evaluates to '/Volumes/Norman Data/me'
# A list of absolute paths to backup. 
include_paths=(
  # "~/.ssh"
  # "~/.bash_history"
  "${HOME}/.bash_profile"
  # "~/.vimrc"
  # "~/.gitconfig"
  # "~/.gitignore"
  # "~/.zshrc"
  # "~/Artifacts"
  "${HOME}/Documents" 
  "--exclude=remote"
  # "~/Downloads"
  # "~/Desktop"
  # "~/Pictures"
  # "~/Projects --exclude 'remote'"
  # "~/Movies"
)

# A list of folder names and files to exclude.
exclude_paths=(
  ".bundle"
  "node_modules"
  "tmp"
)

# Passing list of paths to exclude
for item in "${exclude_paths[@]}"
do
  exclude_flags="${exclude_flags} --exclude=${item}"
done

# Passing list of paths to copy
for item in "${include_paths[@]}"
do
  include_args="${include_args} '${item}'"
done


str="rsync -auvzP ${exclude_flags} ${include_args} ${usr}@${remote_server}:${target_path}"
echo "Running: ${str}"
${str}

実行すると次のようになります:

building file list ... 
rsync: link_stat "/Volumes/Norman" failed: No such file or directory (2)
rsync: link_stat "/Volumes/Norman Data/me/Data/me/.bash_profile" failed: No such file or directory (2)
rsync: link_stat "/Volumes/Norman" failed: No such file or directory (2)
rsync: link_stat "/Volumes/Norman Data/me/Data/me/Documents" failed: No such file or directory (2)
0 files to consider

sent 29 bytes  received 20 bytes  32.67 bytes/sec
total size is 0  speedup is 0.00
rsync error: some files could not be transferred (code 23) at 
/BuildRoot/Library/Caches/com.apple.xbs/Sources/rsync/rsync-52/rsync/main.c(996) [sender=2.6.9]

私の知る限り、myの値のスペースHOMEが問題を引き起こしています。引用符で囲めばスペースがなくなるだろうと考えました"${HOME}/.bash_profile"。そして、どうやらそうなっているようです。つまり、私が得る値echo "Running: ${str}"

rsync -auvzP  --exclude=.bundle --exclude=node_modules --exclude=tmp  '/Volumes/Norman Data/me/.bash_profile' '/Volumes/Norman Data/me/Documents' --exclude=remote [email protected]:backup/

これをターミナルで直接実行するか、スクリプトに貼り付けると( の代わりに${str})、期待どおりに動作します。上記のエラーは、変数を使用する場合にのみ発生します。

ここで何が欠けているのか分かりません。誰か教えていただけませんか?

** 脚本はhttps://gitlab.com/ramawat/randomhacks/blob/master/backup_script.txt

答え1

パラメータを保持するために配列を使用するのは正しいですが、配列を単一の文字列にフラット化しようとしないでください。コマンドとして実行するときに単語に分割する必要があり、引用符の問題が発生するためです。

スクリプト全体で配列を使用するだけです。たとえば、コマンドを配列に蓄積しますcmd

cmd=(rsync -auvzP)
for item in "${exclude_paths[@]}"
do  cmd+=("--exclude=${item}")
done
for item in "${include_paths[@]}"
do  cmd+=("${item}")
done

cmd+=("${usr}@${remote_server}:${target_path}")

set -x
"${cmd[@]}"

set -x最後にを使用すると、シェルが単語を 1 つの引数に保存する方法がわかります。使用されている概念的な引用符が表示されます。

+ rsync ... '/Volumes/Norman Data/me/.bash_profile' ...

関連情報