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

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

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

我需要保留换行符。

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


当前回答

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

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

返回$VAR #换行符

echo "$VAR" #保留换行符

其他回答

你可以避免无用的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可以在命令行中插入选项卡。如果您正在使用编辑器,这取决于哪种编辑器,也可以工作,或者您可能必须关闭自动将制表符转换为空格的功能。

真不敢相信我是第一个发这个的人。

@Erman和@Zombo很接近,但mapfile不只是读取数组…

考虑一下:

#!/bin/bash
mapfile -d '' EXAMPLE << 'EOF'
Hello
こんにちは
今晩は
小夜なら
EOF
echo -n "$EXAMPLE"

收益率:

Hello
こんにちは
今晩は
小夜なら

$ "是给mapfile的分隔符,它永远不会出现,它意味着“未分隔”。

因此,不需要无用地使用cat,也不需要重新组合数组。

此外,你还能得到这样的好处:

$ echo $EXAMPLE
Hello こんにちは 今晩は 小夜なら

你没有收到@Zombo的方法:

mapfile y <<'z'
abc'asdf"
$(dont-execute-this)
foo"bar"''
z
echo $y
abc'asdf"

奖金

如果你通过head -c -1运行它,你也可以用一种不会不性能的方式摆脱最后的换行:

unset EXAMPLE
mapfile -d '' EXAMPLE < <(head -c -1 << EOF
Hello
こんにちは
今晩は
小夜なら
EOF
)
printf "%q" "$EXAMPLE"
$'Hello\nこんにちは\n今晩は\n小夜なら'

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

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

返回$VAR #换行符

echo "$VAR" #保留换行符

从尼尔的回答来看,你通常根本不需要var,你可以像使用变量一样使用函数,而且它比内联或基于读取的解决方案更容易读取。

$ complex_message() {
  cat <<'EOF'
abc'asdf"
$(dont-execute-this)
foo"bar"''
EOF
}

$ echo "This is a $(complex_message)"
This is a abc'asdf"
$(dont-execute-this)
foo"bar"''

将heredoc值赋给变量

VAR="$(cat <<'VAREOF'
abc'asdf"
$(dont-execute-this)
foo"bar"''
VAREOF
)"

用作命令的参数

echo "$(cat <<'SQLEOF'
xxx''xxx'xxx'xx  123123    123123
abc'asdf"
$(dont-execute-this)
foo"bar"''
SQLEOF
)"