How to avoid heredoc expanding variables?
BashEscapingSubstitutionHeredocBash 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'