I made a simple script to perform backup of my NAS. I do it as follows:

date="$(date +%Y-%m-%d)"
newest="$(ls -1td "$base"/*-*-*/ | head -n 1)"

if [ -d "$today" ]; then
  echo "Backup already exists"
  exit 1

echo $newest
echo $dirs

mkdir "$today"
rsync -a --delete --info=progress2 "/myzpool/{$dirs}" "$today" --link-dest="$newest"

So what it is supposed to do is to create a folder with the name of the current date and then copy the folders /myzpool/pub, /myzpool/data and /myzpool/software into this newly created backup folder. But surprisingly, this does not work! rsync aborts with the error rsync: link_stat "/myzpool/{pub,data,software}" failed: No such file or directory.

I don't understand why this happens, because I use a very similar script to backup my virtual server via SSH:

mkdir "$today"
rsync -caz --compress-level=9 -e "ssh -i ~/.ssh/myserver.conf" --delete --info=progress2 "root@myserver.tld:/{$dirs}" "$today" --link-dest="$newest"

and with the virtual server it works just fine. So what is the difference between the two command lines, and how could I fix my script, such that it also works locally?

  • Brace expansion does not happen within double quotes. – Kusalananda May 23 '19 at 17:50
  • So why then does it work when backing up my virtual web server via rsync + ssh? – T. Pluess May 24 '19 at 7:31
  • 1
    In the bash shell, "{$dirs}" would expand to "{srv,opt,home,root,etc}". As far as I know, rsync would then try to access that as the literal name of the file to sync. rsync does no special processing of curly braces. There are examples of using brace expansions in the rsync manual, but those examples relies on the shell to do the expansion, and bash simply won't expand {$dirs} like you'd want due to the order in which expansions happens (brace expansions happen before variable expansions). – Kusalananda May 24 '19 at 7:50
  • I understand that the braces are expanded as you described, this is clear. But I still don't understand why I then "root@myserver.tld:/{$dirs}" is valid, while "/myzpool/{$dirs}" isn't. In both cases the brace expansion happens, but rsync doesn't accept the first command line (copying local files), while it does accept the latter (copying from a remote server). – T. Pluess May 24 '19 at 9:29
  • Quoted brace expensing works for rsync in this case because there is another level of shell evaluation - on the remote server. – roaima Sep 20 '19 at 19:37

I just had a similar problem and have determined that Brace Expansion does work inside Command Substitution.

The problem is that Brace Expansion occurs before anything else so the rsync needs to be run like eval rsync ... so that the Brace Expansion is done a second time.

See this answer for more details...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.