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.

What needs to be done to ensure that a parameter containing embedded spaces is handled correctly when used within a command substitution? Perhaps an example will illustrate

$ file="/home/1_cr/xy z"
$ basename $file
xy

$ #need to pass basename a quoted $file to prevent the z in 'xy z' from being eaten
$ basename "$file"
xy z

$ #Now using $file inside a command substitution without quoting.....
$ #....the command substitution causes 'xy z' to split
$ set -- $(basename "$file")
$ printf "%s\n" "$@"
xy
z

$ #But quoting the command substitution does not prevent 'xy z'...... 
$ #....from being split before being passed to basename
$ set -- "$(basename $file)"
$ printf "%s\n" "$@"
xy

What do i need to do so that

$ set -- $(basename $file)
$ printf "%s\n" "$@"

yields

xy z   
share|improve this question
1  
set -- "$(basename "$file")"? At least this works on my system. –  Joseph R. Nov 12 '13 at 22:40
    
@JosephR. lol...and I thought i would have to do something a lot more complicated. Do you know how the word-splitting plays out with your solution? –  1_CR Nov 12 '13 at 22:43
    
The internal quotes simply protect $file from word expansion when passed to basename as in your own example. Just because you quoted the command substitution doesn't mean everything inside it is immune to word expansion. –  Joseph R. Nov 12 '13 at 22:47
    
@JosephR. thanks! See my comment against Gilles answer –  1_CR Nov 13 '13 at 0:48
add comment

2 Answers 2

up vote 5 down vote accepted

You need to put double quotes around all variable and command substitutions.

set -- "$(basename -- "$file")"

If you allow the value of the variable to be split into words and these words to be treated as glob patterns, there's no going back. You can no longer tell how much whitespace was there or whether the file names were the result of a wildcard expansion. You can't turn the hamburger back into a cow, so you must make sure not to send the cow to the abattoir in the first place.

share|improve this answer
    
Thanks. What threw me off was the difference in the way bash handles nested double-quotes in set -- "xy "$file"" versus set -- "$(basename -- "$file")". So when command substitution comes into play, bash is able to interpret nested quotes "naturally"? –  1_CR Nov 13 '13 at 0:44
1  
@1_CR Yes (provided you use the $(…) form of command substitution, and not the obsolescent backquotes). –  Gilles Nov 13 '13 at 0:51
add comment

You have several options,

  1. Use "$"* instead "$@"

     set -- $(basename "$file")
     printf "%s\n" "$*"
    
  2. Quote the command substitution and the variable,

     set -- "$(basename "$file")"
     printf "%s\n" "$@"
    
share|improve this answer
4  
Really shouldn't use #1 as it can still produce unreliable results. #2 is only way :-) –  Patrick Nov 12 '13 at 23:00
add comment

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.