I tried to write a very simple synchronizing script that uses rsync with some params. I wanted these params to be stored in a variable in my script. Here is a minimal example:
$tree
.
├── a
│ └── aaa_p=1_k=1
│ └── x.txt
├── b
│ └── aaa_p=1_k=1
│ └── x.txt
└── script.sh
$cat script.sh
#!/bin/bash
PARAMS="--exclude '*p=*'"
rsync -av ${PARAMS} ./a/* ./b/
But when I run script.sh
, it synchronizes x.txt
, although x.txt
it resides in a path containing p=
that should be excluded. At the same time, when I run from command line:
rsync -av --exclude '*p=*' ./a/* ./b/
then the exclude
is respected, and synchronization does not happen.
What do I do badly in the script, so the exclude
switch is not taken into account? Is it variable substitution in Bash?
When you type --exclude '*p=*' ./a/* ./b/
in your terminal the '
quotes are removed by bash. rsync
sees only the string *p=*
. But when you write PARAMS="--exclude '*p=*'"; rsync -av ${PARAMS}
the quotes inside the variable stay, telling rsync
to exlcude files that start and end with a '
.
You could leave out the '
quotes inside the variable, but the *
would expand before rsync
runs (this was also the case before, but '*p*'
probably didn't match any file). You could quote "$PARAMS"
to avoid expanding *
, but then the whole string --exclude *p=*
would be treated as one argument.
The correct way to go about this is to use an array:
params=(--exclude '*p=*')
rsync -av "${params[@]}" ./a/* ./b/