bash \n 在 heredoc 中的变量
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/28090477/
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
\n in variable in heredoc
提问by Kamil Roman
Is there any way to for a Bash heredoc to interpret '\n\' in a heredoc?
有没有办法让 Bash 继承人在继承人中解释 '\n\' ?
I have an iteratively built string in a loop, something like
我在循环中有一个迭代构建的字符串,类似于
for i in word1 word2 word3
do
TMP_VAR=$i
ret="$ret\n$TMP_VAR"
done
and then I want to use the created string in a heredoc:
然后我想在 heredoc 中使用创建的字符串:
cat <<EOF > myfile
HEADER
==
$ret
==
TRAILER
EOF
however I would like to interpret the "\n" character as newline, so that the output is
但是我想将“\n”字符解释为换行符,以便输出
HEADER
==
word1
word2
word3
==
TRAILER
instead of
代替
HEADER
==
\nword1\nword2\nword3
==
TRAILER
Is it possible? Or should I perhaps build my initial string somehow otherwise?
是否可以?或者我应该以其他方式构建我的初始字符串?
回答by Tom Fenech
In bash you can use $'\n'
to add a newline to a string:
在 bash 中,您可以使用$'\n'
向字符串添加换行符:
ret="$ret"$'\n'"$TMP_VAR"
You can also use +=
to append to a string:
您还可以使用+=
附加到字符串:
ret+=$'\n'"$TMP_VAR"
回答by kojiro
As others (and other answers to other questions) have said, you can put encoded characters into a string for the shell to interpret.
正如其他人(以及其他问题的其他答案)所说,您可以将编码的字符放入字符串中,以便 shell 进行解释。
x=$'\n' # newline
printf -v x '\n' # newline
That said, I don't believe there is any way to directly put an encoded newline into a heredoc.
也就是说,我不相信有任何方法可以将编码的换行符直接放入heredoc 中。
cat <<EOF
\n
EOF
just outputs a literal \n
只输出一个文字 \n
cat <<$'EOF'
…
EOF
is nothing special, nor is <<'EOF'
没什么特别的,也不是 <<'EOF'
The best you can do is to preencode the newline, and include the expansion in the heredoc:
您能做的最好的事情是对换行符进行预编码,并在heredoc 中包含扩展:
nl=$'\n'
cat <<EOF
foo bar $nl baz
EOF
outputs
输出
foo bar
baz
回答by mvrht
Change:
改变:
==
$ret
==
to:
到:
==
$(echo -e $ret)
==
回答by rici
The best solution is to build your variable with actual newlines, instead of inserting character sequences which need to be replaced with newlines.
最好的解决方案是用实际的换行符构建变量,而不是插入需要用换行符替换的字符序列。
I find the following function sufficiently useful that I put it in my bash startup file; for you simple case, it would work perfectly:
我发现以下功能非常有用,因此我将其放入我的 bash 启动文件中;对于你简单的情况,它会完美地工作:
lines() { printf %s\n "$@"; }
With that, you could write:
有了这个,你可以写:
ret=$(lines word1 word2 word3)
instead of the loop you use. Then you can insert $ret
into the heredoc and it will work as expected. [See note 1]
而不是您使用的循环。然后你可以插入$ret
到 heredoc 中,它会按预期工作。[见注1]
However, if for whatever reason you really want to construct your string with escape sequences instead of actual characters, you can do the expansion using an extended feature in the bash printf
built-in, the %b
format code. %b
does almostthe same escape conversions, but there are a couple of differences. See help printf
for details. Using that you could do the following:
但是,如果出于某种原因,您确实想使用转义序列而不是实际字符来构造字符串,则可以使用 bashprintf
内置%b
格式代码中的扩展功能进行扩展。%b
执行几乎相同的转义转换,但有一些差异。详情请参阅help printf
。使用它,您可以执行以下操作:
$ ret="word1\nword2\nword3"
$ cat <<EOF > tmp
> HEADER
> ==
> $(printf "%b" "$ret")
> ==
> TRAILER
> EOF
$ cat tmp
HEADER
==
word1
word2
word3
==
TRAILER
Notes
笔记
There is a subtlety in the use of the
lines
function.printf
keeps repeating its format string until it absorbs all of its arguments, so that the format%s\\n
puts a newline after everyargument, including the last one. For most use cases, that's exactly what you want; most of my uses of lines have to do with feeding the result into a utility which expects lines of inputs.But in the case of
ret=$(lines word1 word2 word3)
, I didn't really want the trailing newline, since my plan is to insert$ret
on a line by itself in the here doc. Fortunately, command substitution ($(...)
) always deletes trailing newlines from the output of the command, so the value ofret
after the assignment has newlines betweenthe arguments, but not at the end. (This feature is occasionally annoying but more often it is exactly what you wanted, so it goes unnoticed.)
lines
函数的使用有一个微妙之处。printf
不断重复它的格式字符串,直到它吸收所有参数,以便格式%s\\n
在每个参数后放置一个换行符,包括最后一个。对于大多数用例,这正是您想要的;我对线的大部分使用都与将结果输入到需要输入线的实用程序有关。但是在 的情况下
ret=$(lines word1 word2 word3)
,我真的不想要尾随换行符,因为我的计划是$ret
在此处的文档中单独插入一行。幸运的是,命令替换 ($(...)
) 总是从命令的输出中删除尾随的换行符,因此ret
赋值之后的值在参数之间有换行符,但在末尾没有。(此功能偶尔会令人讨厌,但更多时候它正是您想要的,因此不会引起注意。)
回答by adoreste
Using awk '{print}'
solves the problem for me.
使用awk '{print}'
为我解决了问题。
cat << EOF |
line1
line2
line3
EOF
awk '{print}' > outputfile
# outputfile contents
cat outputfile
line1
line2
line3