Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

I'm running this kind of code:

#!/usr/bin/env bash
set -u
exclude1='--exclude=/path/*'
exclude2='--exclude=/path with spaces/*'
exclude3=''        # any 'exclude' can be empty
tar -czf backup.tgz "$exclude1" "$exclude2" "$exclude3" 2>&1 | grep -i 'my_reg_exp' > error.log
RESULT=("${PIPESTATUS[@]}")
... etc ...

When I run this code, I get this error:

tar: : Cannot stat: No such file or directory

This is because "$exclude3" is translated as an empty argument. Exactly as if I did this:

tar -czf backup.tgz "$exclude1" "$exclude2" ''

One way to avoid this error is to remove the double quotes around $excludeX. But this is a problem if $excludeX contains any space or other strange characters.

Another way would be to use eval but because I need to keep the double quotes, I don't see how to suppress the quotes AND the empty arguments when needed.

The only solution I found is to construct the command-line with string concatenation:

CMD='tar -czf backup.tgz'
if [[ -n "$exclude1" ]]; then CMD+=" \"$exclude1\" "; fi
if [[ -n "$exclude2" ]]; then CMD+=" \"$exclude2\" "; fi
if [[ -n "$exclude3" ]]; then CMD+=" \"$exclude3\" "; fi
eval $CMD 2>&1 | grep -i 'my_reg_exp' > error.log
RESULT=("${PIPESTATUS[@]}")
... etc ...

Anyone have a smarter idea?

share|improve this question

2 Answers 2

up vote 7 down vote accepted
tar -czf backup.tgz "$exclude1" "$exclude2" ${exclude3+"$exclude3"} 2>&1

${exclude3+"$exclude3"} expands to nothing, if $exclude3 is unset, and to "$exclude3", if it is set.

(and similarly for the other variables that are potentially unset.)

Note that there is a difference between an unset variable and a variable that is set to the empty string, so you should use

unset exclude3

instead of

exclude3=''
share|improve this answer
1  
Nice trick, but if $exclude3 is unset then Bash will issue an error because 'set -u' is used as a safety measure. –  Gregory MOUSSAT Apr 28 '13 at 0:11
    
It works as long as you only test whether the variable is set or not. Testing doesn't count as trying to perform parameter expansion on the variable. –  Uwe Apr 28 '13 at 0:21
1  
By the way, there is a related construction that treats unset and empty variables in the same way, namely ${exclude3:+"$exclude3"} (note the colon). –  Uwe Apr 28 '13 at 0:38

Since you're working in bash, use an array.

excludes=()
excludes+=('--exclude=/path/*')
…
tar -czf backup.tgz "${excludes[@]}"

If you have an optional entry in some variable, add it in a conditional.

if [[ -n $exclude_or_empty ]]; then excludes+=("$exclude_or_empty"); fi
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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