Home > Blockchain >  How to get optional quotes for rsync in script
How to get optional quotes for rsync in script

Time:01-10

I'm trying to programmatically use rsync and all is well until you have spaces in the paths. Then I have to quote the path in the script which is also fine until it's optional.

In this case --link-dest can be optional and I've tried variations to accommodate it in both cases of it being there and not but I'm having problems when paths need to be quoted.

One option would be to use a case statement and just call rsync with two different lines but there are other rsync options that may or may not be there and the combinations could add up quickly so a better solution would be nice. Since this is my machine and no one but me has access to it I'm not concerned about security so if an eval or something is the only way that's fine.

#!/bin/bash

src='/home/x/ll ll'
d1='/home/x/rsy nc/a'
d2='/home/x/rsy nc/b'

rsync -a "$src" "$d1"

# Try 1
x1='--link-dest='
x2='/home/x/rsy nc/a'
rsync -a $x1"$x2"  "$src" "$d2" 

This works until you don't have a --link-dest which will look like this:

x1=''
x2=''
rsync -a $x1"$x2"  "$src" "$d2" 

And rsync takes the empty "" as the source so it fails.

# Try 2
x1='--link-dest="'
x2='/home/x/rsy nc/a"'
rsync -a $x1$x2  "$src" "$d2" 

This fails because double quotes in x1 & x2 are taken as part of the path and so it creates a path not found error but it does of course work like this:

x1=''
x2=''
rsync -a $x1$x2  "$src" "$d2" 

I've tried a couple of other variations but they all come back to the two issues above.

CodePudding user response:

You can use Bash arrays to solve this kind of problem.

# inputs come from wherever
src='/home/x/ll ll'
d1='/home/x/rsy nc/a'
d2='/home/x/rsy nc/b'
x2='something'
# or
x2=''

# build the command
my_cmd=(rsync -a)
if [[ $x2 ]]; then
   my_cmd =("--link-dest=$x2")
fi
my_cmd =("$src" "$d2")

# run the command
"${my_cmd[@]}"

First I'm constructing the command bit by bit, with quotes carefully used to preserve multi-word options as such, storing each option/argument as an element in my array, including the rsync command itself.

Then I invoke it with the weird "${my_cmd[@]}" syntax, which means expand all the elements of the array, without re-splitting multi-word elements. Note that the quotes are important: if you remove them, the multiple word values in the array get split again and you're back to square one.

The syntax "${my_cmd[*]}" also exists, but that one joins the whole array into a single word, again now what you want. You need the [@] to get each array element expanded as its own word in the result.

Google "bash arrays" for more details.

  • Related