0

I have this minimal working example of shell script that won't exclude cache directory.

#!/bin/sh

SRC_DIR="/home/" DEST_DIR="/backup/test" OPTSTR="-avzHAXx --delete --exclude '.cache'"

rsync $OPTSTR $SRC_DIR $DEST_DIR

But, if you write that open, then it works.

#!/bin/sh

rsync -avzHAXx --delete --exclude '.cache' /home/ /backup/test

What's the problem?

Raimo
  • 11

1 Answers1

3

Your issue has to do with the way you use your string $OPTSTR. This is a string of multiple space-separated words, and since you use it unquoted, you make the shell split it into a list of separate words. However, the shell will not perform an extra quote removal step, so the single quotes in the string will be literal. You command therefore excludes files and directories named '.cache', not .cache. You would also have issue had you needed to use strings with spaces in them, or globbing patterns.

In short: Do not put separate things, that needs to be kept separate, in a single string.

Instead, use a list:

#!/bin/sh

src_dir=/home dest_dir=/backup/test

set -- -v -a -x -HAX --delete --exclude='.cache/'

rsync "$@" "$src_dir/" "$dest_dir"

This sets the list of positional parameters to the options that you later want to use with rsync. Each parameter will be correctly handled, even if it contains quoted string with embedded spaces and globbing characters, as long as the expansion of $@ is double quoted.

Or, if you use bash, you may use a named array,

#!/bin/bash

src_dir=/home dest_dir=/backup/test

opts=( -v -a -x -HAX --delete --exclude='.cache/' )

rsync "${opts[@]}" "$src_dir/" "$dest_dir"

Also related:

Kusalananda
  • 333,661