我有这个多行字符串(包括引号):

abc'asdf"
$(dont-execute-this)
foo"bar"''

我将如何分配它到一个变量使用heredoc在Bash?

我需要保留换行符。

我不想转义字符串中的字符,这将是恼人的…


当前回答

你可以避免无用的cat使用,并更好地处理不匹配的引号:

$ read -r -d '' VAR <<'EOF'
abc'asdf"
$(dont-execute-this)
foo"bar"''
EOF

如果回显时不引用变量,则会丢失换行符。引用它来保存它们:

$ echo "$VAR"
abc'asdf"
$(dont-execute-this)
foo"bar"''

如果您想在源代码中使用缩进来提高可读性,请在小于号之后使用破折号。缩进必须只使用制表符(没有空格)。

$ read -r -d '' VAR <<-'EOF'
    abc'asdf"
    $(dont-execute-this)
    foo"bar"''
    EOF
$ echo "$VAR"
abc'asdf"
$(dont-execute-this)
foo"bar"''

相反,如果希望保留结果变量内容中的制表符,则需要从IFS中删除制表符。这里文档(EOF)的终端标记不能缩进。

$ IFS='' read -r -d '' VAR <<'EOF'
    abc'asdf"
    $(dont-execute-this)
    foo"bar"''
EOF
$ echo "$VAR"
    abc'asdf"
    $(dont-execute-this)
    foo"bar"''

通过按Ctrl-V Tab可以在命令行中插入选项卡。如果您正在使用编辑器,这取决于哪种编辑器,也可以工作,或者您可能必须关闭自动将制表符转换为空格的功能。

其他回答

仍然没有保留换行符的解决方案。

这不是真的——你可能只是被echo的行为误导了:

返回$VAR #换行符

echo "$VAR" #保留换行符

这是Dennis方法的变化,在脚本中看起来更优雅。

函数定义:

define(){ IFS='\n' read -r -d '' ${1} || true; }

用法:

define VAR <<'EOF'
abc'asdf"
$(dont-execute-this)
foo"bar"''
EOF

echo "$VAR"

享受

附注:为不支持read -d的shell创建了一个“read循环”版本。应该适用于set -eu和未配对的反引号,但测试不太好:

define(){ o=; while IFS="\n" read -r a; do o="$o$a"'
'; done; eval "$1=\$o"; }

这里有一种非常优雅的方法,可以避免uoc:

  VAR=$(sed -e 's/[ ]*\| //g' -e '1d;$d' <<'--------------------'
      | 
      | <!DOCTYPE html>
      | <html>
      |   <head>
      |     <script src='script.js'></script>
      |   </head>
      |   <body>
      |     <span id='hello-world'></span>
      |   </body>
      | </html>
      | 
--------------------
    )

'|'字符定义了空白,打印的字符串中只尊重空白右侧的空白。'1d;$d'去掉第一行和最后一行,它们只是作为内容周围的上下边距添加的。所有内容都可以缩进到您喜欢的任何级别,除了HEREDOC分隔符,在本例中它只是一堆连字符。

echo "$VAR"

# prints

<!DOCTYPE html>
<html>
  <head>
    <script src='script.js'></script>
  </head>
  <body>
    <span id='hello-world'></span>
  </body>
</html>

你可以避免无用的cat使用,并更好地处理不匹配的引号:

$ read -r -d '' VAR <<'EOF'
abc'asdf"
$(dont-execute-this)
foo"bar"''
EOF

如果回显时不引用变量,则会丢失换行符。引用它来保存它们:

$ echo "$VAR"
abc'asdf"
$(dont-execute-this)
foo"bar"''

如果您想在源代码中使用缩进来提高可读性,请在小于号之后使用破折号。缩进必须只使用制表符(没有空格)。

$ read -r -d '' VAR <<-'EOF'
    abc'asdf"
    $(dont-execute-this)
    foo"bar"''
    EOF
$ echo "$VAR"
abc'asdf"
$(dont-execute-this)
foo"bar"''

相反,如果希望保留结果变量内容中的制表符,则需要从IFS中删除制表符。这里文档(EOF)的终端标记不能缩进。

$ IFS='' read -r -d '' VAR <<'EOF'
    abc'asdf"
    $(dont-execute-this)
    foo"bar"''
EOF
$ echo "$VAR"
    abc'asdf"
    $(dont-execute-this)
    foo"bar"''

通过按Ctrl-V Tab可以在命令行中插入选项卡。如果您正在使用编辑器,这取决于哪种编辑器,也可以工作,或者您可能必须关闭自动将制表符转换为空格的功能。

VAR=<<END
abc
END

不工作,因为你将stdin重定向到不关心它的东西,即赋值

export A=`cat <<END
sdfsdf
sdfsdf
sdfsfds
END
` ; echo $A

有用,但里面有个背部痉挛可能会阻止你使用这个。另外,你应该避免使用反引号,最好使用命令替换符号$(..)。

export A=$(cat <<END
sdfsdf
sdfsdf
sdfsfds
END
) ; echo $A