1

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.

huangyingw
  • 89
  • 6
  • Don't use strings, use arrays of strings; that way you also don't need `eval`. See [BashFAQ #50](https://mywiki.wooledge.org/BashFAQ/050), and -- on-point for why `eval` is best avoided -- [BashFAQ #48](https://mywiki.wooledge.org/BashFAQ/048). – Charles Duffy Jan 23 '22 at 22:09
  • 1
    That said, you shouldn't be using the `bash` tag for a question about `zsh`. They're very different shells, and not mutually compatible. (If you _do_ mean to be using bash, change the shebang from `#!/bin/zsh` to `#!/usr/bin/env bash`). – Charles Duffy Jan 23 '22 at 22:10
  • We've had a lot of previous questions about storing arguments for `rsync` in variables, but most concern bash rather than zsh ([1](https://stackoverflow.com/questions/29527983), [2](https://stackoverflow.com/questions/22030280), [3](https://stackoverflow.com/questions/5253782), [4](https://stackoverflow.com/questions/50710476), ...). With both bash and zsh, the answer is: use an array rather than a plain string variable. – Gordon Davisson Jan 24 '22 at 00:58
  • thanks for your comments, I just changed the title, and tag. I mainly use zsh now. – huangyingw Jan 24 '22 at 06:43

2 Answers2

1

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/"
markp-fuso
  • 28,790
  • 4
  • 16
  • 36
  • thanks, I choose ro=($(< rsync_basic_options)), I just trim the spaces between "(" "$", and ")", this should be ok, right? mapfile dosen't work in macos – huangyingw Jan 24 '22 at 06:49
  • yes, removing those spaces is fine in this scenario; I just added the extra spaces for readability; I don't have access to a macos env but from what I've seen in other Q&As this type of issue (old and/or not-installed binaries) is a recurring theme with the plain vanilla, basic macos; in some cases (eg, `bash`, `GNU awk)` it's possible to install newer software; `mapfile` is a `bash` builtin so if you're open to working with `bash` you could probably get a newer version installed into macos; I don't use `zsh` so I'm not sure what `zsh` might have as an equivalent to `mapfile` – markp-fuso Jan 24 '22 at 19:36
0

one solution I found is:

copy.sh:

#!/bin/zsh

source=$1
target=$2

. ~/loadrc/bashrc/rsync_basic_option.sh

rsync \
    "${rsync_basic_option[@]}" \
    "$source/" "$target/"

rsync_basic_option.sh:

#!/bin/zsh

rsync_basic_option=(
    -aHSv \
        --progress \
        --force \
        --append-verify \
    )

it seems to work, so far so good, is this the best way to achieve this?

huangyingw
  • 89
  • 6
  • This should work, but as Charles Duffy said bash and zsh are very different shells, and having zsh stuff in a directory named "bashrc" suggests some basic confusion. (Although this particular syntax will work in both bash and zsh.) – Gordon Davisson Jan 24 '22 at 01:00
  • sorry, "bashrc" is confusing.. 90% of my scripts are using zsh now, while they still reside under "bashrc" folder.. move all of them are time-consuming and maybe cause some other bugs.. since I am the only user of my scripts... I am a little lazy to change this, until I have to .. – huangyingw Jan 24 '22 at 06:46