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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1167746/
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-09 18:20:31  来源:igfitidea点击:

How to assign a heredoc value to a variable in Bash?

bashheredoc

提问by Neil

I have this multi-line string (quotes included):

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

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

How would I assign it to a variable using a heredoc in Bash?

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

I need to preserve newlines.

我需要保留换行符。

I don't want to escape the characters in the string, that would be annoying...

我不想转义字符串中的字符,那会很烦人...

回答by Paused until further notice.

You can avoid a useless use of catand handle mismatched quotes better with this:

您可以通过以下方式避免无用的使用cat并更好地处理不匹配的引号:

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

If you don't quote the variable when you echo it, newlines are lost. Quoting it preserves them:

如果在回显时不引用变量,则换行符将丢失。引用它可以保留它们:

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

If you want to use indentation for readability in the source code, use a dash after the less-thans. The indentation must be done using only tabs (no spaces).

如果要在源代码中使用缩进以提高可读性,请在小于号后使用破折号。缩进必须仅使用制表符(无空格)。

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

If, instead, you want to preserve the tabs in the contents of the resulting variable, you need to remove tab from IFS. The terminal marker for the here doc (EOF) must not be indented.

相反,如果您想在结果变量的内容中保留制表符,则需要从IFS. here 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"''

Tabs can be inserted at the command line by pressing Ctrl-VTab. If you are using an editor, depending on which one, that may also work or you may have to turn off the feature that automatically converts tabs to spaces.

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

回答by Neil

Use $() to assign the output of catto your variable like this:

使用 $() 将 的输出分配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

Making sure to delimit starting END_HEREDOC with single-quotes.

确保用单引号分隔开始 END_HEREDOC。

Note that ending heredoc delimiter END_HEREDOCmust be alone on the line (hence ending parenthesis is on the next line).

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

Thanks to @ephemientfor the answer.

感谢您@ephemient的回答。

回答by ttt

this is variation of Dennis method, looks more elegant in the scripts.

这是丹尼斯方法的变体,在脚本中看起来更优雅。

function definition:

函数定义:

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

usage:

用法:

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

echo "$VAR"

enjoy

请享用

p.s. made a 'read loop'version for shells that do not support read -d. should work with set -euand unpaired backticks, but not tested very well:

PS做了一个“读圈”版本不支持炮弹read -d。应该使用set -eu未配对的反引号,但没有很好地测试:

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

回答by l0st3d

VAR=<<END
abc
END

doesn't work because you are redirecting stdin to something that doesn't care about it, namely the assignment

不起作用,因为您将标准输入重定向到不关心它的东西,即分配

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

works, but there's a back-tic in there that may stop you from using this. Also, you should really avoid using backticks, it's better to use the command substitution notation $(..).

工作,但那里有一个后退可能会阻止你使用它。此外,您真的应该避免使用反引号,最好使用命令替换符号$(..)

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

回答by patspam

There is still no solution that preserves newlines.

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

This is not true - you're probably just being misled by the behaviour of echo:

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

echo $VAR # strips newlines

echo $VAR # strips newlines

echo "$VAR" # preserves newlines

echo "$VAR" # preserves newlines

回答by dimo414

Branching off Neil's answer, you often don't need a var at all, you can use a function in much the same way as a variable and it's much easier to read than the inline or read-based solutions.

Neil 的答案中分离出来,您通常根本不需要 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"''

回答by Steven Penny

An array is a variable, so in that case mapfile will work

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

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

Then you can print like this

然后你可以像这样打印

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

回答by bronze man

assign a heredoc value to a variable

为变量分配一个 heredoc 值

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

used as an argument of a command

用作命令的参数

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

回答by Orwellophile

I found myself having to read a string with NULL in it, so here is a solution that will read anythingyou throw at it. Although if you actually are dealing with NULL, you will need to deal with that at the hex level.

我发现自己必须读取一个包含 NULL 的字符串,所以这里有一个解决方案可以读取你扔给它的任何东西。尽管如果您实际上正在处理 NULL,您将需要在十六进制级别处理它。

$ cat > read.dd.sh

$ cat > 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 )
}

Proof:

证明:

$ . 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 example (with ^J, ^M, ^I):

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

回答by Brad Parks

Thanks to dimo414's answer, this shows how his great solution works, and shows that you can have quotes and variables in the text easily as well:

感谢dimo414 的回答,这显示了他出色的解决方案是如何工作的,并表明您也可以轻松地在文本中使用引号和变量:

example output

示例输出

$ ./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

   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