bash 如何避免heredoc扩展变量?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/27920806/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 21:50:23  来源:igfitidea点击:

How to avoid heredoc expanding variables?

bashescapingsubstitutionheredoc

提问by TheCodeKiller

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

我正在尝试使用来自 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
"

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

它的结果是不好,因为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=,"


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
#
### 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
"

results in:

结果是:

#!/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}"


Wanted/attended result whould have been :

通缉/参加的结果应该是:

#!/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}"

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

解决方法是在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
"

回答by fedorqui 'SO stop harming'

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

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

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

From man bash:

来自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 \ is ignored, and \ must be used to quote the characters \, $, and `.

这里的文件

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

here-document 的格式为:

      <<[-]word
              here-document
      delimiter

不会对 word 执行参数扩展、命令替换、算术扩展或路径名扩展。如果word中的任何字符被引用,则分隔符是word上引用去除的结果,并且here-document中的行没有被扩展。 如果 word 未加引号,则此处文档的所有行都经过参数扩展、命令替换和算术扩展。在后一种情况下,字符序列 \ 将被忽略,并且必须使用 \ 来引用字符 \、$ 和 `。

回答by Marc Bredt

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 命令时,将命令本身放在单引号中,然后用反斜杠转义 $。占位符变量必须在命令 bash 上下文中设置(在 su 之后)。所以你需要做某事

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