如何在Bash中为变量分配heredoc值?

时间:2009-07-22 19:43:31

标签: bash heredoc

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

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

如何在Bash中使用heredoc将其分配给变量?

我需要保留换行符。

我不想逃避字符串中的字符,这会很烦人......

11 个答案:

答案 0 :(得分:438)

您可以避免无用地使用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中删除选项卡。此处doc(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 在命令行插入选项卡。如果您使用的是编辑器,可能还可以使用编辑器,或者您可能必须关闭自动将标签转换为空格的功能。

答案 1 :(得分:184)

使用$()将cat的输出分配给您的变量,如下所示:

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

# this will echo variable with new lines intact
echo "$VAR"
# this will echo variable without new lines (changed to space character)
echo $VAR

确保使用单引号分隔END_HEREDOC的开头。

请注意,结束heredoc分隔符END_HEREDOC必须单独在行上(因此结束括号在下一行)。

感谢@ephemient的回答。

答案 2 :(得分:73)

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

功能定义:

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

用法:

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

echo "$VAR"

享受

P.S。为不支持read -d的shell创建了一个'read loop'版本。应该使用set -eu不成对反引号,但未经过良好测试:

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

答案 3 :(得分:27)

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

答案 4 :(得分:27)

在此处添加评论作为答案,因为我没有足够的代表点来评论您的问题文本。

  

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

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

echo $VAR # strips newlines

echo "$VAR" # preserves newlines

答案 5 :(得分:9)

分支Neil's answer,你通常根本不需要var,你可以像变量一样使用函数,它比内联或read更容易阅读基于解决方案。

$ 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"''

答案 6 :(得分:8)

数组是一个变量,因此在这种情况下mapfile将起作用

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

然后你可以像这样打印

printf %s "${y[@]}"

答案 7 :(得分:3)

将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
)"

答案 8 :(得分:1)

我发现自己必须读取一个包含NULL的字符串,所以这里有一个解决方案,可以读取你抛出的任何。虽然如果你真的在处理NULL,你需要在十六进制级别处理它。

$ cat&gt; read.dd.sh

read.dd() {
     buf= 
     while read; do
        buf+=$REPLY
     done < <( dd bs=1 2>/dev/null | xxd -p )

     printf -v REPLY '%b' $( sed 's/../ \\\x&/g' <<< $buf )
}

证明:

$ . read.dd.sh
$ read.dd < read.dd.sh
$ echo -n "$REPLY" > read.dd.sh.copy
$ diff read.dd.sh read.dd.sh.copy || echo "File are different"
$ 

HEREDOC示例(使用^ J,^ M,^ I):

$ read.dd <<'HEREDOC'
>       (TAB)
>       (SPACES)
(^J)^M(^M)
> DONE
>
> HEREDOC

$ declare -p REPLY
declare -- REPLY="  (TAB)
      (SPACES)
(^M)
DONE

"

$ declare -p REPLY | xxd
0000000: 6465 636c 6172 6520 2d2d 2052 4550 4c59  declare -- REPLY
0000010: 3d22 0928 5441 4229 0a20 2020 2020 2028  =".(TAB).      (
0000020: 5350 4143 4553 290a 285e 4a29 0d28 5e4d  SPACES).(^J).(^M
0000030: 290a 444f 4e45 0a0a 220a                 ).DONE

答案 9 :(得分:0)

感谢dimo414's answer,这表明他的优秀解决方案如何运作,并且表明您可以轻松地在文本中添加引号和变量:

示例输出

$ ./test.sh

The text from the example function is:
  Welcome dev: Would you "like" to know how many 'files' there are in /tmp?

  There are "      38" files in /tmp, according to the "wc" command

test.sh

#!/bin/bash

function text1()
{
  COUNT=$(\ls /tmp | wc -l)
cat <<EOF

  $1 Would you "like" to know how many 'files' there are in /tmp?

  There are "$COUNT" files in /tmp, according to the "wc" command

EOF
}

function main()
{
  OUT=$(text1 "Welcome dev:")
  echo "The text from the example function is: $OUT"
}

main

答案 10 :(得分:-8)

$TEST="ok"
read MYTEXT <<EOT
this bash trick
should preserve
newlines $TEST
long live perl
EOT
echo -e $MYTEXT