我有一个 Bash 脚本,计划运行该脚本进行每日备份(我的主目录是 /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
在最后使用,你会看到 shell 如何将单词保留到单个参数中。它向你展示了它正在使用的概念引用:
+ rsync ... '/Volumes/Norman Data/me/.bash_profile' ...