Bash – Word-splitting when parameter is used within command substitution

bashcommand-substitutionquotingshell

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   

Best Answer

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.