
Tengo un script Bash que planeo ejecutar para copias de seguridad diarias (mi INICIO es /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}
Ejecutar eso resulta en:
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]
Hasta donde puedo decir, el espacio en el valor de my HOME
está causando problemas. Pensé que citarlo "${HOME}/.bash_profile"
cuidaría los espacios. Y parece que sí. Con esto quiero decir que el valor que obtengo echo "Running: ${str}"
es
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/
Y cuando lo ejecuto directamente en la terminal o lo pego en el script (en lugar de ${str}
, funciona como se esperaba. Los errores anteriores solo ocurren cuando se usa la variable.
Parece que no puedo entender lo que me estoy perdiendo aquí. ¿Alguien puede arrojar algo de luz?
** guión adaptado dehttps://gitlab.com/ramawat/randomhacks/blob/master/backup_script.txt
Respuesta1
Tiene razón al usar matrices para contener parámetros, pero no debe intentar aplanar las matrices en una sola cadena, ya que luego será necesario dividirla en palabras cuando se ejecute como un comando, y se producirán problemas con las comillas.
Simplemente use matrices en todo el script, por ejemplo, acumule el comando en matriz 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[@]}"
Si usa set -x
al final, verá cómo el shell conserva las palabras en un solo argumento. Le muestra la cotización teórica que está utilizando:
+ rsync ... '/Volumes/Norman Data/me/.bash_profile' ...