
Eu tenho um script Bash que pretendo executar para backups diários (meu 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}
Executar isso resulta em:
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]
Pelo que sei, o espaço no valor my HOME
está causando problemas. Achei que citá-lo assim "${HOME}/.bash_profile"
cuidaria dos espaços. E parece que sim. Com isso quero dizer que o valor que obtenho 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/
E quando executo isso diretamente no terminal ou colo no script (no lugar de ${str}
, funciona conforme o esperado. Os erros acima só acontecem ao usar a variável.
Não consigo descobrir o que estou perdendo aqui. Alguém pode lançar alguma luz?
** roteiro adaptado dehttps://gitlab.com/ramawat/randomhacks/blob/master/backup_script.txt
Responder1
Você está certo em usar matrizes para armazenar parâmetros, mas não deve tentar nivelar as matrizes em uma única string, pois isso precisará ser dividido em palavras quando executado como um comando, e ocorrerão problemas de cotação.
Basta usar arrays em todo o script, por exemplo, acumular o comando em array 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[@]}"
Se você usar set -x
no final verá como o shell está preservando as palavras em um único argumento. Ele mostra a citação nocional que está usando:
+ rsync ... '/Volumes/Norman Data/me/.bash_profile' ...