Search code examples
zshevalrsync

How to wrap a multiple options string in zsh


I have multiple bash scripts which would use rsync to transfer files. they are mirror.sh, move.sh, copy.sh. I want them to share some basic common rsync options.

copy.sh:

#!/bin/zsh

rsync_basic_option=$(~/loadrc/bashrc/rsync_basic_option.sh)
echo "rsync_basic_option --> $rsync_basic_option"

rsync \
    "$rsync_basic_option" \
    "$source/" "$target/"

rsync_basic_option.sh:

#!/bin/zsh

echo \
    -aHSv \
    --progress \
    --force \
    --append-verify \

after running it:

./copy.sh ~/loadrc/ ~/loadrc.bak/

I got following error output:

rsync_basic_option --> -aHSv --progress --force --append-verify
rsync: -aHSv --progress --force --append-verify: unknown option
rsync error: syntax or usage error (code 1) at main.c(1766) [client=3.2.3]

how to achieve this? one alternative is use eval. I could wrap a long COMMAND string, and then call it with

    eval "$COMMAND"

Fix me if incorrect: I feel the usage of eval is very dangerous, buggy. if there is any space inside "$COMMAND", or "$source", "$target", it would cause un-expected result. so, I don't want to use eval.


Solution

  • Slight variation based on assumption there aren't any other commands or variable assignments in the current rsync_basic_options.sh file:

    $ cat rsync_basic_options
    -aHSv
    --progress
    --force
    --append-verify
    

    There are then a few options for loading these into an array; a couple that come to mind:

    $ ro=( $(< rsync_basic_options) )       # might be problematic if dealing with embedded white space
    
    # or
    
    $ mapfile -t ro < rsync_basic_options
    

    Both of these populate the ro[] array with the following:

    $ typeset -p ro
    declare -a ro=([0]="-aHSv" [1]="--progress" [2]="--force" [3]="--append-verify")
    

    Which can then be used in the script like such:

    rsync "${ro[@]}" "$source/" "$target/"