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.

Given this piece of bash:

PARMS='-rvu'
PARMS+=" --delete --exclude='.git'"
echo $PARMS
rsync ${PARMS} . ${TARGET}

The echo shows the PARMS string as expected, no error is displayed, but rsync silently acts as if the options added by the += did not exist. However, this works as expected:

PARMS='-rvu'
rsync ${PARMS} --delete --exclude='.git' . ${TARGET}

I guess I screwed something up with bash quotes (always had problems with those), but not exactly sure what and why are the options ignored even though the string seems to have been built correctly.

share|improve this question
1  
echo "$PARMS" and rsync "${PARMS}"... –  jasonwryan Aug 28 at 7:37
    
This works for me with bash version 4.2.25 without any changes. –  Anthon Aug 28 at 7:41

2 Answers 2

up vote 12 down vote accepted

There is a difference between:

PARMS+="... --exclude='.git'"

and

... --exclude='.git'

In the first, the single quotes are inside quotes themselves, so they are literally present in the substituted text given to rsync as arguments. rsync gets an argument whose value is --exclude='.git'. In the second, the single quotes are interpreted by the shell at the time they're written, because they aren't inside quotes themselves, and rsync gets to see --exclude=.git.

In this case, you don't need the single quotes at all — .git is a perfectly valid shell word on its own, with no special characters, so you can use it literally in the command.

Better for this kind of thing, though, is an array:

PARMS=(-rvu)
PARMS+=(--delete --exclude='.git')
rsync "${PARMS[@]}"

This builds up your command as separate words, with whatever quoting you want interpreted at the time you write the array line. "${PARMS[@]}" expands to each entry in the array as a separate argument, even if the argument itself has special characters or spaces in it, so rsync sees what you wrote as you meant it.

share|improve this answer
    
bash performed word spliting after ${PARMS} was expanded. So the single quote was also interpreted by the shell. –  cuonglm Aug 28 at 7:50
2  
Try it! I did. The quotes remain, and if there were spaces in between they are split points anyway. –  Michael Homer Aug 28 at 7:55
    
@Gnouc: From the bash man page: "Quote Removal: After the preceding expansions, all unquoted occurrences of the characters \ , ', and " that did not result from one of the above expansions are removed." "above expansions" includes Parameter Expansion which performs the expansion of ${PARMS}. –  camh Aug 28 at 7:59
    
Thanks. So I understand that in that case omitting the single quotes inside the double ones will work but for completeness' sake - what if I needed to quote some special characters and didn't want to use your latter approach? –  neuviemeporte Aug 28 at 8:08
    
If your special characters are not part of IFS (generally, whitespace), you don't need to quote them. If they are, you're out of luck unless you hack something together with eval — this is a bit of a misfeature in general, and arrays are the right way to deal with it. –  Michael Homer Aug 28 at 8:11

In addition to @Michael Homer's answer, you can use bash eval function:

PARMS='-rvu'
PARMS+=" --delete --exclude='.git'"
echo "$PARMS"
eval "rsync ${PARMS} . "'"${TARGET}"'
share|improve this answer
1  
You can, but you shouldn't. Arrays were added specifically to avoid this use of eval. –  chepner Aug 29 at 21:45

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.