2

I try to generate a command line for a backup script on bash shell.

Simple example:

EXCLUDES="/home/*/.cache/* /var/cache/* /var/tmp/* /var/lib/lxcfs/cgroup/*"; 
for FOLDER in $EXCLUDES; do printf -- '--exclude %b\n' "$FOLDER" ; done

Should result in:

--exclude '/home/*/.cache/*' --exclude '/var/cache/*' --exclude '/var/tmp/*' --exclude '/var/lib/lxcfs/cgroup/*'

But the problem is, that the folders get expanded from shell. I did try many examples with echo / printf / quoting / IFS... but without the right result.

Any way to fix this?

4

Whenever you have to specify a list of pathnames or pathnames with filename globs, or just generally a list that you are intending to loop over and/or use as a list of arguments to some command, use an array.

If you don't use an array but a string, you will not be able to process things with spaces in them (because you use spaces as the delimiter in the string). It also makes it hard to loop over the contents of the string as you will have to invoke word splitting (by not quoting the variable expansion). But this will also cause filename globbing to happen, unless you explicitly turn this off with set -f.

In most shells, even in plain /bin/sh, use an array instead. In sh, use the array of positional parameters ($@).

For bash, use an array of quoted strings, like

excludes=( '/home/*/.cache/*'
           '/var/cache/*'
           '/var/tmp/*'
           '/var/lib/lxcfs/cgroup/*' )

Then,

rsync_opts=( --verbose --archive )
for excl in "${excludes[@]}"; do
    rsync_opts+=( --exclude="$excl" )
done

Later,

rsync "${rsync_opts[@]}" source/ target

Note that the quoting is important in all of the above variable expansions. The expansion "${array[@]}" (as well as "$@" below) results in a list of individually quoted elements of the array in question (but only if double quoted!).

For any /bin/sh shell:

set -- '/home/*/.cache/*'  \
       '/var/cache/*'      \
       '/var/tmp/*'        \
       '/var/lib/lxcfs/cgroup/*'

for excl do
    set -- "$@" --exclude="$excl"
    shift
done
set -- --verbose --archive "$@"

rsync "$@" source/ target

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.