如何在 Bash 中将定界符值赋给变量?
我有这个多行字符串(包括引号):
abc'asdf"
$(dont-execute-this)
foo"bar"''
如何在 Bash 中使用定界文档将其分配给变量?
我需要保留换行符。
我不想转义字符串中的字符,那会很烦人......
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?
I need to preserve newlines.
I don't want to escape the characters in the string, that would be annoying...
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(15)
这是一种(恕我直言)非常优雅并且避免 UUOC 的方法:
“|” 字符定义边距,并且在打印字符串中仅考虑边距右侧的空白。
'1d;$d'
删除第一行和最后一行,它们只是作为内容周围的顶部和底部边距添加。 所有内容都可以缩进到您喜欢的任何级别,但 HEREDOC 分隔符除外,在本例中它只是一堆连字符。Here's a way to do it that is (imho) quite elegant and avoids a UUOC:
The '|' characters define the margin, and only the whitespace to the right of the margin is respected in the printed string. The
'1d;$d'
strips the first and last line, which are just added as a top and bottom margin around the content. Everything can be indented to whatever level you like, except the HEREDOC delimiter, which in this case is just a bunch of hyphens.您可以避免无用地使用
cat
并通过以下方式更好地处理不匹配的引号:如果在回显变量时不引用该变量,则会丢失换行符。 引用它可以保留它们:
如果您想在源代码中使用缩进以提高可读性,请在小于号后使用破折号。 缩进必须仅使用制表符(不能使用空格)完成。
相反,如果您想保留结果变量内容中的制表符,则需要从
IFS
中删除制表符。 此处文档的终止标记 (EOF
) 不得缩进。可以通过按 Ctrl-V Tab 在命令行插入制表符。 如果您使用的是编辑器(具体取决于哪个编辑器),这也可能有效,或者您可能必须关闭自动将制表符转换为空格的功能。
You can avoid a useless use of
cat
and handle mismatched quotes better with this:If you don't quote the variable when you echo it, newlines are lost. Quoting it preserves them:
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).
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.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.
使用 $() 将
cat
的输出分配给您的变量,如下所示:确保用单引号分隔起始 END_HEREDOC。防止扩展heredoc的内容,因此
dont-execute-this
将不会被执行。请注意,结束这里文档分隔符
END_HEREDOC
必须单独出现在该行中(因此结束括号)
位于下一行)。感谢
@ephemient
的回答。Use $() to assign the output of
cat
to your variable like this:Making sure to delimit starting END_HEREDOC with single-quotes. This will prevent the content of the heredoc from being expanded, so
dont-execute-this
will not be executed.Note that ending heredoc delimiter
END_HEREDOC
must be alone on the line (hence the ending parenthesis)
is on the next line).Thanks to
@ephemient
for the answer.这是丹尼斯方法的变体,在脚本中看起来更优雅。
函数定义(bash 版本):
用法:
更新ksh“读循环”版本(也适用于 bash):
测试(还包括不删除最后一个换行符): https://gist.github.com/ootada/e80b6d7fb86acdcda75d77eb7ade364c
享受
\n'; done; o=${o%?}; eval "$1=\$o"; }测试(还包括不删除最后一个换行符): https://gist.github.com/ootada/e80b6d7fb86acdcda75d77eb7ade364c
享受
\n' read -r -d '' ${1} || true; }用法:
更新ksh“读循环”版本(也适用于 bash):
测试(还包括不删除最后一个换行符): https://gist.github.com/ootada/e80b6d7fb86acdcda75d77eb7ade364c
享受
\n' $(dont-exec ute-this) foo " bar " ' ' `bad bad `` EOF echo "$VAR"更新ksh“读循环”版本(也适用于 bash):
测试(还包括不删除最后一个换行符): https://gist.github.com/ootada/e80b6d7fb86acdcda75d77eb7ade364c
享受
\n' read -r -d '' ${1} || true; }用法:
更新ksh“读循环”版本(也适用于 bash):
测试(还包括不删除最后一个换行符): https://gist.github.com/ootada/e80b6d7fb86acdcda75d77eb7ade364c
享受
this is variation of Dennis method, looks more elegant in the scripts.
function definition (bash version):
usage:
Updated ksh 'read loop' version (also works on bash):
Tests (also includes versions that does not remove the last newline): https://gist.github.com/ootada/e80b6d7fb86acdcda75d77eb7ade364c
enjoy
\n'; done; o=${o%?}; eval "$1=\$o"; }Tests (also includes versions that does not remove the last newline): https://gist.github.com/ootada/e80b6d7fb86acdcda75d77eb7ade364c
enjoy
\n' read -r -d '' ${1} || true; }usage:
Updated ksh 'read loop' version (also works on bash):
Tests (also includes versions that does not remove the last newline): https://gist.github.com/ootada/e80b6d7fb86acdcda75d77eb7ade364c
enjoy
\n' $(dont-exec ute-this) foo " bar " ' ' `bad bad `` EOF echo "$VAR"Updated ksh 'read loop' version (also works on bash):
Tests (also includes versions that does not remove the last newline): https://gist.github.com/ootada/e80b6d7fb86acdcda75d77eb7ade364c
enjoy
\n' read -r -d '' ${1} || true; }usage:
Updated ksh 'read loop' version (also works on bash):
Tests (also includes versions that does not remove the last newline): https://gist.github.com/ootada/e80b6d7fb86acdcda75d77eb7ade364c
enjoy
不起作用,因为您将标准输入重定向到不关心它的东西,即作业
有效,但其中有一个反引号可能会阻止您使用它。 另外,您确实应该避免使用反引号,最好使用命令替换符号
$(..)
。doesn't work because you are redirecting stdin to something that doesn't care about it, namely the assignment
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
$(..)
.这不是真的 - 您可能只是被 echo 的行为误导了:
echo $VAR # strips newlines
echo "$VAR" # keeps newlines
This is not true - you're probably just being misled by the behaviour of echo:
echo $VAR # strips newlines
echo "$VAR" # preserves newlines
分支 Neil 的回答,您通常根本不需要 var,您可以以大致相同的方式使用函数作为变量,它比内联或基于读取的解决方案更容易读取。
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.数组是一个变量,所以在这种情况下,mapfile 将起作用
然后你可以像这样打印
An array is a variable, so in that case mapfile will work
Then you can print like this
我不敢相信我是第一个发布此内容的人。
@Erman 和 @Zombo 很接近,但是
mapfile
不仅仅读取数组...考虑一下:
Yielding:
$''
是给mapfile 的分隔符
,它永远不会发生,它的意思是“未分隔”。因此,不需要无用地使用
cat
,也不需要承受重新组合数组的惩罚。此外,您还可以获得以下好处:
这是 @Zombo 的方法所没有的:
奖励
如果您通过
head -c -1
运行它,您还可以以一种不会的方式摆脱最后一个换行符。不表现不佳:I can't believe I'm the first to post this.
@Erman and @Zombo are close, but
mapfile
doesn't just read arrays...Consider this:
Yielding:
$''
is the delimiter given tomapfile
, it will never occur, it means "not delimited".So there's no need for a useless use of
cat
and no need to incur the penalty of recombining arrays.Furthermore, you get this benefit:
Which you do not receive with @Zombo's method:
Bonus
If you run it through
head -c -1
you can also get rid of that last newline in a way that won't be non-performant:将heredoc值分配给
用作命令参数的变量
assign a heredoc value to a variable
used as an argument of a command
感谢 dimo414 的回答,这展示了他出色的解决方案的工作原理,并表明您可以轻松地在文本中包含引号和变量还有:
示例输出
test.sh
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:
example output
test.sh
在许多情况下,此页面的答案过于复杂:
In many cases, this page has over-complex answers:
我发现自己必须读取其中包含 NULL 的字符串,因此这里有一个解决方案,可以读取您扔给它的任何内容。 尽管如果您实际上正在处理 NULL,则需要在十六进制级别处理它。
$猫> read.dd.sh
证明:
HEREDOC 示例(带有 ^J、^M、^I):
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.
$ cat > read.dd.sh
Proof:
HEREDOC example (with ^J, ^M, ^I):
这将在任何 POSIX shell 中工作,避免
read
的非零退出状态问题,并且看起来比内联cat
更干净。警告:这将删除此处文档末尾的换行符。 不在末尾的换行符将被保留。
This will work in any POSIX shell, avoids the issue of the non-zero exit status of
read
, and looks cleaner than an inlinecat
.Caveat: This will strip newlines at the end of the here-doc. Newlines that are not at the end will be preserved.