Search code examples
bashshellcommand-line

Why does command substitution work in these ways?


In my .bashrc file I have the following:

export USER_HOME1='/home/$(id -nu)/' 
export USER_HOME2='/home/'$(id -nu)'/'
export USER_HOME3="/home/$(id -nu)/"
export USER_HOME4="/home/\$(id -nu)/"

Command substitution only works for USER_HOME2 and USER_HOME3. How does it work for USER_HOME2?

Within single quotes, the '$' is treated as a literal character instead of taking on any special meaning. Within double quotes, certain characters take on special meaning and require escaping if we need to use them literally. This would explain why command substitution works in USER_HOME3 but not in USER_HOME1 and USER_HOME4.

How does USER_HOME2 work? How does the shell know how to pair up the single quotes? Does it effectively concatenate three strings: '/home/', the output of $(id -nu), and '/'? In which case, we can rewrite USER_HOME2 as

export USER_HOME2=/home/$(id -nu)/ 

Solution

  • How does USER_HOME2 work? How does the shell know how to pair up the single quotes? Does it effectively concatenate three strings: '/home/', the output of $(id -nu), and '/'? In which case, we can rewrite USER_HOME2 as

    Yes, that's exactly what's happening. The following strings are all identical from the viewpoint of the shell:

    • abc
    • 'abc'
    • "abc"
    • 'a'b'c'
    • "a"b"c"
    • ''abc''
    • 'ab''c'
    • 'ab'"c"

    Command substitution must be double quoted, otherwise field splitting and glob expansion will be applied to the result (unless when it appears on the right hand side of the parameter assignment; in that case no further expansions will be applied)