如何将一个heredoc值分配给Bash中的variables?

我有这个多行string(包括引号):

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

我如何将它分配给variables在Bash中使用heredoc?

我需要保留换行符。

我不想逃避string中的字符,这将是烦人的…

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

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

如果在回显variables时不引用variables,则换行符将丢失。 引用它保留了它们:

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

如果您想在源代码中使用缩进以提高可读性,请在减less语句之后使用短划线。 缩进必须只使用制表符(不能有空格)。

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

相反,如果您想要保留结果variables内容中的选项卡,则需要从IFS删除选项卡。 这里doc( EOF )的terminal标记不能缩进。

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

通过按CtrlV Tab键,可以在命令行插入标签 。 如果您使用的是编辑器,则取决于哪一个编辑器也可以工作,或者您可能不得不closures自动将制表符转换为空格的function。

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

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

确保使用单引号分隔END_HEREDOC。

感谢@ephemient的答案。

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

function定义:

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

用法:

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

请享用

ps为不支持read -d shell创build了“读循环”版本。 应该使用set -eu不成对的反引号 ,但是没有很好的testing:

 define(){ o=; while IFS="\n" read -ra; do o="$o$a"' '; done; eval "$1=\$o"; } 
 VAR=<<END abc END 

不起作用,因为你正在将stdinredirect到不关心它的事情上,即赋值

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

工作,但是有一个在那里可能会阻止你使用这个back-tic。 另外,你应该避免使用反引号,最好使用命令replace符$(..)

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

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

仍然没有解决scheme,保留换行符。

这不是真的 – 你可能只是被回声的行为误导了:

echo $VAR # strips newlines

echo "$VAR" # preserves newlines

分配一个heredoc值给一个variables

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

一个数组是一个variables,所以在这种情况下mapfile将工作

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

然后你可以打印这样的

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

Neil的答案分支,你通常不需要一个变种,你可以使用一个函数在很大程度上作为一个variables,它比内联或基于read的解决scheme更容易阅读。

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

我发现自己不得不阅读一个NULL的string,所以这里是一个解决scheme,将读取任何你扔在它。 虽然如果你实际上正在处理NULL,你将需要在hex级别处理。

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

certificate:

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

感谢dimo414的回答 ,这显示了他伟大的解决scheme是如何工作的,并且表明你可以很容易地在文本中引用引号和variables:

示例输出

 $ ./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 
 $TEST="ok" read MYTEXT <<EOT this bash trick should preserve newlines $TEST long live perl EOT echo -e $MYTEXT