如何在Bash中为变量赋值?

时间:2022-04-28 15:42:38

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中,我如何将它分配给一个变量?

I need to preserve newlines.

我需要保存换行符。

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

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

11 个解决方案

#1


372  

You can avoid a useless use of cat and 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).

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

$ 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中删除选项卡。此处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-V Tab. 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-V选项卡插入命令行。如果您正在使用一个编辑器(取决于哪个编辑器),那么它也可以工作,或者您可能需要关闭自动将制表符转换为空格的特性。

#2


121  

Use $() to assign the output of cat to 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_HEREDOC must be alone on the line (hence ending parenthesis is on the next line).

请注意,在这条线上,必须单独使用结束本文档分隔符END_HEREDOC(因此结束括号在下一行)。

Thanks to @ephemient for the answer.

感谢@ephemient的回复。

#3


70  

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

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

function definition:

函数定义:

define(){ IFS='\n' read -r -d '' ${1} || 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 -eu and unpaired backticks, but not tested very well:

p.s.为不支持read -d的shell制作了一个“读循环”版本。应该使用set -eu和未配对的背勾,但测试不是很好:

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

#4


25  

VAR=<<END
abc
END

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

不工作是因为你将stdin重定向到不关心它的东西,也就是作业

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

#5


22  

Adding comment here as an answer since I don't have enough rep points to comment on your question text.

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

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 #删除换行

echo "$VAR" # preserves newlines

echo“$VAR”#保存新行

#6


6  

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[@]}"

#7


5  

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,您可以像使用变量一样使用函数,并且它比内联或基于读的解决方案更容易读取。

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

#8


4  

assign a heredoc value to a variable

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

#9


1  

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

我发现我必须读取一个带空值的字符串,所以这里有一个解可以读取你向它抛出的任何东西。尽管如果您实际处理的是NULL,那么您将需要在十六进制级别处理它。

$ cat > read.dd.sh

$猫> 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 ^,^,^我):

$ 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

#10


0  

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

  $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

#11


-7  

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

#1


372  

You can avoid a useless use of cat and 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).

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

$ 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中删除选项卡。此处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-V Tab. 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-V选项卡插入命令行。如果您正在使用一个编辑器(取决于哪个编辑器),那么它也可以工作,或者您可能需要关闭自动将制表符转换为空格的特性。

#2


121  

Use $() to assign the output of cat to 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_HEREDOC must be alone on the line (hence ending parenthesis is on the next line).

请注意,在这条线上,必须单独使用结束本文档分隔符END_HEREDOC(因此结束括号在下一行)。

Thanks to @ephemient for the answer.

感谢@ephemient的回复。

#3


70  

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

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

function definition:

函数定义:

define(){ IFS='\n' read -r -d '' ${1} || 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 -eu and unpaired backticks, but not tested very well:

p.s.为不支持read -d的shell制作了一个“读循环”版本。应该使用set -eu和未配对的背勾,但测试不是很好:

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

#4


25  

VAR=<<END
abc
END

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

不工作是因为你将stdin重定向到不关心它的东西,也就是作业

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

#5


22  

Adding comment here as an answer since I don't have enough rep points to comment on your question text.

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

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 #删除换行

echo "$VAR" # preserves newlines

echo“$VAR”#保存新行

#6


6  

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[@]}"

#7


5  

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,您可以像使用变量一样使用函数,并且它比内联或基于读的解决方案更容易读取。

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

#8


4  

assign a heredoc value to a variable

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

#9


1  

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

我发现我必须读取一个带空值的字符串,所以这里有一个解可以读取你向它抛出的任何东西。尽管如果您实际处理的是NULL,那么您将需要在十六进制级别处理它。

$ cat > read.dd.sh

$猫> 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 ^,^,^我):

$ 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

#10


0  

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

  $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

#11


-7  

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