Search code examples
stringbashshellvariablesheredoc

Heredoc: Passing a string with a variable and multiple "$" characters


I want to pass a string in a heredoc that contains a variable, and multiple "$" characters. The command without the heredoc is:

FOO='BAR'
echo ${FOO}: '$NOT_A_VARIABLE'

The FOO variable is correctly substituted and the '$NOT_A_VARIABLE' string avoids substitution because it is single quoted. The command returns as expected:

BAR: $NOT_A_VARIABLE

Now if I do the same inside the heredoc:

sh << EOF
   echo ${FOO}: '$NOT_A_VARIABLE'
EOF

The output is not what I desired:

BAR:

It seems, that the '$NOT_A_VARIABLE' is substituted even though it is surrounded by single quotes.

I know that this can be avoid by escaping the $ with a backslash: \$ but this solution is annoying since there might be multiple $ characters randomly distributed in the string.

I wonder if there is a smart use of quotes (single/double) or other solutions that might fix it.


Solution

  • The contents of your here document are treated as a double-quoted string, just as if you had written

    echo "$FOO: '$NOT_A_VARIABLE'" | sh
    

    If you want to suppress all parameter expansion in the here document, you can quote the delimiter:

    sh << 'EOF'
        echo ${FOO}: '$NOT_A_VARIABLE'
    EOF
    

    which will pass

    echo ${FOO}: '$NOT_A_VARIABLE'
    

    as the input to sh.

    If you only want to suppress a specific expansion, escape the $ just as you would in a double-quoted string.

    # echo "$FOO: \$NOT_A_VARIABLE" | sh
    sh << EOF
       echo ${FOO}: \$NOT_A_VARIABLE
    EOF