如何避免heredoc扩展变量?

The*_*ler 60 bash escaping heredoc substitution

我正在尝试使用来自ENV的替换字符串创建脚本文件,但也希望防止一些​​转义

export PLACEHOLDER1="myPlaceholder1Value"
export PLACEHOLDER2="myPlaceholder2Value"
sudo /bin/su -c "cat << EOF > /etc/init.d/my-script
#!/bin/bash
#
### BEGIN INIT INFO
# Provides:          my-script
# Required-Start:    \$remote_fs \$syslog
# Required-Stop:     \$remote_fs \$syslog
# Should-Start:      \$network \$time
# Should-Stop:       \$network \$time
# Default-Start:     2 3 4 5 
# Default-Stop:      0 1 6
# Short-Description: blabla
# Description:       bla bla desc
#
### END INIT INFO
#
myvariable_1=toto$PLACEHOLDER1
myvariable_2=titi$PLACEHOLDER2
myvariable_final=\"dynamicvar=\${myvariable_1},\${myvariable_2}\"
EOF
"
Run Code Online (Sandbox Code Playgroud)

由于myvariable_final没有被转义并被替换为init脚本依赖项中的一个($ remote_fs,$ syslog,$ network,$ time),因此结果不好.

#!/bin/bash
#
### BEGIN INIT INFO
# Provides:          my-script
# Required-Start:
# Required-Stop:
# Should-Start:
# Should-Stop:
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: blabla
# Description:       bla bla desc
#
### END INIT INFO
#
myvariable_1=totomyPlaceholder1Value
myvariable_2=titimyPlaceholder2Value
myvariable_final="dynamicvar=,"
Run Code Online (Sandbox Code Playgroud)

如果我试图\在美元背后加一个反斜杠$,我设法避免替换,但我得到了一个不必要的反斜杠\:

export PLACEHOLDER1="myPlaceholder1Value"
export PLACEHOLDER2="myPlaceholder2Value"
sudo /bin/su -c "cat << EOF > /etc/init.d/my-script
#!/bin/bash
#
### BEGIN INIT INFO
# Provides:          my-script
# Required-Start:    \$\remote_fs \$\syslog
# Required-Stop:     \$remote_fs \$syslog
# Should-Start:      \$network \$time
# Should-Stop:       \$network \$time
# Default-Start:     2 3 4 5 
# Default-Stop:      0 1 6
# Short-Description: blabla
# Description:       bla bla desc
#
### END INIT INFO
#
myvariable_1=toto$PLACEHOLDER1
myvariable_2=titi$PLACEHOLDER2
myvariable_final=\"dynamicvar=\$\{myvariable_1},\$\{myvariable_2}\"
EOF
"
Run Code Online (Sandbox Code Playgroud)

结果是:

#!/bin/bash
#
### BEGIN INIT INFO
# Provides:          my-script
# Required-Start:    $\remote_fs $\syslog
# Required-Stop:
# Should-Start:
# Should-Stop:
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: blabla
# Description:       bla bla desc
#
### END INIT INFO
#
myvariable_1=totomyPlaceholder1Value
myvariable_2=titimyPlaceholder2Value
myvariable_final="dynamicvar=$\{myvariable_1},$\{myvariable_2}"
Run Code Online (Sandbox Code Playgroud)

想要/参加的结果应该是:

#!/bin/bash
#
### BEGIN INIT INFO
# Provides:          my-script
# Required-Start:    $remote_fs $syslog
# Required-Stop:     $remote_fs $syslog
# Should-Start:      $network $time
# Should-Stop:       $network $time
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: blabla
# Description:       bla bla desc
#
### END INIT INFO
#
myvariable_1=totomyPlaceholder1Value
myvariable_2=titimyPlaceholder2Value
myvariable_final="dynamicvar=${myvariable_1},${myvariable_2}"
Run Code Online (Sandbox Code Playgroud)

通过在下面的EOF周围放置引号并使用反斜杠来控制需要时的转义来解决

export PLACEHOLDER1="myPlaceholder1Value"
export PLACEHOLDER2="myPlaceholder2Value"
sudo /bin/su -c "cat << 'EOF' > /etc/init.d/my-script
#!/bin/bash
#
### BEGIN INIT INFO
# Provides:          my-script
# Required-Start:    \$remote_fs \$syslog
# Required-Stop:     \$remote_fs \$syslog
# Should-Start:      \$network \$time
# Should-Stop:       \$network \$time
# Default-Start:     2 3 4 5 
# Default-Stop:      0 1 6
# Short-Description: blabla
# Description:       bla bla desc
#
### END INIT INFO
#
myvariable_1=toto$PLACEHOLDER1
myvariable_2=titi$PLACEHOLDER2
myvariable_final=\"dynamicvar=\${myvariable_1},\${myvariable_2}\"
EOF
"
Run Code Online (Sandbox Code Playgroud)

fed*_*qui 151

只是'EOF'用来防止变量扩展:

sudo /bin/su -c "cat << 'EOF' > /etc/init.d/my-script
#                       ^   ^
Run Code Online (Sandbox Code Playgroud)

来自man bash:

这里的文件

这种类型的重定向指示shell从当前源读取输入,直到看到仅包含分隔符(没有尾随空白)的行.然后,读取到该点的所有行都将用作命令的标准输入.

here-documents的格式是:

      <<[-]word
              here-document
      delimiter
Run Code Online (Sandbox Code Playgroud)

不对字执行参数扩展,命令替换,算术扩展或路径名扩展.如果引用单词中的任何字符,则分隔符是单词上的引号删除的结果,并且不会展开here-document中的行. 如果word不加引号,则here-document的所有行都要进行参数扩展,命令替换和算术扩展.在后一种情况下,字符序列\被忽略,\必须用于引用字符\,$和`.

  • 最后我发现我做错了什么。“EOF”应该仅用于开始标记。不适用于结束标签。只需使用不带引号的“EOF” (6认同)
  • 围绕'EOF'的引用就像逃避一样,我可以控制什么是替换,而wnat没有被替换 (4认同)

Mar*_*edt 6

使用 su 命令时,请将命令本身放在单引号中,并用反斜杠转义 $。占位符变量必须在命令 bash 上下文中设置(在 su 之后)。所以你需要做某事

su -c 'ph="ph"; cat << EOF > script 
varinscript=$ph
var=\${var}
EOF'
Run Code Online (Sandbox Code Playgroud)