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

$ #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" "$@"

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

What do i need to do so that

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


xy z   
  • 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? – iruvar 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 – iruvar Nov 13 '13 at 0:48

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.

  • 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"? – iruvar Nov 13 '13 at 0:44
  • 2
    @1_CR Yes (provided you use the $(…) form of command substitution, and not the obsolescent backquotes). – Gilles Nov 13 '13 at 0:51

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" "$@"
  • 4
    Really shouldn't use #1 as it can still produce unreliable results. #2 is only way :-) – Patrick Nov 12 '13 at 23:00

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.