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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-18 12:14:11  来源:igfitidea点击:

\n in variable in heredoc

bashvariablesescapingheredoc

提问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 $retinto 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 printfbuilt-in, the %bformat code. %bdoes almostthe same escape conversions, but there are a couple of differences. See help printffor 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

笔记

  1. There is a subtlety in the use of the linesfunction. printfkeeps repeating its format string until it absorbs all of its arguments, so that the format %s\\nputs 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 $reton a line by itself in the here doc. Fortunately, command substitution ($(...)) always deletes trailing newlines from the output of the command, so the value of retafter 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.)

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