How to avoid heredoc expanding variables?

BashEscapingSubstitutionHeredoc

Bash Problem Overview


I'm trying to create a script file using substitution string from ENV but want also to prevent some from escaping

export PLACEHOLDER1="myPlaceholder1Value"
sudo /bin/su -c "cat << EOF > /etc/init.d/my-script
#!/bin/bash

myvariable_1=toto$PLACEHOLDER1
myvariable_final=\"dynamicvar=\${myvariable_1},\${myvariable_2}\"
EOF
"

It results in which is not good as the myvariable_final are not escaped and substituted as the one from the init script dependencies ($remote_fs, $syslog, $network, $time)

#!/bin/bash

myvariable_1=totomyPlaceholder1Value
myvariable_2=titimyPlaceholder2Value
myvariable_final="dynamicvar=,"

If i try to put a backslash \ behind the dollars $, I manage to avoid the substitution but I getting an unwanted backslash \:

export PLACEHOLDER1="myPlaceholder1Value"
export PLACEHOLDER2="myPlaceholder2Value"
sudo /bin/su -c "cat << EOF > /etc/init.d/my-script
#!/bin/bash

myvariable_1=toto$PLACEHOLDER1
myvariable_2=titi$PLACEHOLDER2
myvariable_final=\"dynamicvar=\$\{myvariable_1},\$\{myvariable_2}\"
EOF
"

results in:

#!/bin/bash

myvariable_1=totomyPlaceholder1Value
myvariable_2=titimyPlaceholder2Value
myvariable_final="dynamicvar=$\{myvariable_1},$\{myvariable_2}"

Wanted/attended result whould have been :

#!/bin/bash

myvariable_1=totomyPlaceholder1Value
myvariable_2=titimyPlaceholder2Value
myvariable_final="dynamicvar=${myvariable_1},${myvariable_2}"

solved by putting quote around the EOF as below and using backslash to control the escaping when needed

export PLACEHOLDER1="myPlaceholder1Value"
export PLACEHOLDER2="myPlaceholder2Value"
sudo /bin/su -c "cat << 'EOF' > /etc/init.d/my-script
#!/bin/bash

myvariable_1=toto$PLACEHOLDER1
myvariable_2=titi$PLACEHOLDER2
myvariable_final=\"dynamicvar=\${myvariable_1},\${myvariable_2}\"
EOF
"

Bash Solutions


Solution 1 - Bash

Just use 'EOF' to prevent the variable from expanding:

sudo /bin/su -c "cat << 'EOF' > /etc/init.d/my-script
#                       ^   ^

From man bash:

> Here Documents > > This type of redirection instructs the shell to read input from the > current source until a line containing only delimiter (with no > trailing blanks) is seen. All of the lines read up to that point are > then used as the standard input for a command. > > The format of here-documents is: > > <<[-]word > here-document > delimiter > > No parameter expansion, command substitution, arithmetic expansion, > or pathname expansion is performed on word. If any characters in word > are quoted, the delimiter is the result of quote removal on word, and > the lines in the here-document are not expanded. If word is > unquoted, all lines of the here-document are subjected to parameter > expansion, command substitution, and arithmetic expansion. In the > latter case, the character sequence \<newline> is ignored, and \ > must be used to quote the characters \, $, and `.

Solution 2 - Bash

when using the su command put the command itself in sigle quotes and just escape the $ with a backslash. the placeholder variables has to set in command bash context (here after su). so you need to do sth like

su -c 'ph="ph"; cat << EOF > script 
varinscript=$ph
var=\${var}
EOF'

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionTheCodeKillerView Question on Stackoverflow
Solution 1 - BashfedorquiView Answer on Stackoverflow
Solution 2 - BashMarc BredtView Answer on Stackoverflow