problemas com espaços na variável de ambiente no script rsync no MacOS

problemas com espaços na variável de ambiente no script rsync no MacOS

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 HOMEestá 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 -xno 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' ...

informação relacionada