1

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.

1
  • 3
    bash doesn't parse the heredoc, so it can either expand all variables, or none. Commented Jan 19, 2022 at 17:40

1 Answer 1

4

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
Sign up to request clarification or add additional context in comments.

4 Comments

Actually, the quoted heredoc outputs BAR: $NOT_A_VARIABLE if FOO is exported and : $NOT_A_VARIABLE otherwise. The quoted heredoc suppresses variable expansion for the current shell, but the child sh process will evaluate its input as code, repecting the unquoted variable and the single quoted one.
Reworded the answer to emphasize what the shell's input will be without worrying about the output of the shell.
Nice. I suppose the OP needs to decide at what level that variable ought to be expanded: in the current shell or the child shell.
Thanks for the explanations. I was hoping for a solution more elegant and compact than escaping every $ with \ . I will al least escape all $ instances automatically with sed 's/\$/\\$/g'.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.