\ n在heredoc变量中

时间:2015-01-22 13:53:30

标签: bash variables escaping heredoc

有没有办法让Bash heredoc在heredoc中解释'\ n \'?

我在循环中有一个迭代构建的字符串,类似于

for i in word1 word2 word3
do
        TMP_VAR=$i
        ret="$ret\n$TMP_VAR"
done

然后我想在heredoc中使用创建的字符串:

cat <<EOF > myfile
HEADER
==
$ret
==
TRAILER
EOF

但是我想将“\ n”字符解释为换行符,以便输出为

HEADER
==
word1
word2
word3
==
TRAILER

而不是

HEADER
==
\nword1\nword2\nword3
==
TRAILER

有可能吗?或者我应该以某种方式建立我的初始字符串?

5 个答案:

答案 0 :(得分:8)

在bash中,您可以使用$'\n'向字符串添加换行符:

ret="$ret"$'\n'"$TMP_VAR"

您还可以使用+=附加到字符串:

ret+=$'\n'"$TMP_VAR"

答案 1 :(得分:5)

正如其他人(以及其他问题的其他答案)所说,您可以将编码后的字符放入字符串中供shell解释。

x=$'\n' # newline
printf -v x '\n' # newline

那就是说,我不相信有任何方法可以直接将编码的换行符放入 heredoc

cat <<EOF
\n
EOF

只输出文字\n

cat <<$'EOF'
…
EOF

没什么特别的,也不是<<'EOF'

您可以做的最好的事情是对换行符进行预编码,并将扩展包含在heredoc中:

nl=$'\n'
cat <<EOF
foo bar $nl baz
EOF

输出

foo bar
 baz

答案 2 :(得分:5)

变化:

==
$ret
==

为:

==
$(echo -e $ret)
==

答案 3 :(得分:4)

最好的解决方案是使用实际换行符构建变量,而不是插入需要用换行符替换的字符序列。

我发现以下功能非常有用,我把它放在我的bash启动文件中;对于你的简单案例,它会完美地运作:

lines() { printf %s\\n "$@"; }

有了这个,你可以写:

ret=$(lines word1 word2 word3)

而不是你使用的循环。然后,您可以将$ret插入到heredoc中,它将按预期工作。 [见注1]

但是,如果由于某种原因你真的想用转义序列而不是实际字符构造你的字符串,你可以使用内置的bash printf中的扩展功能进行扩展,{{1}格式代码。 %b 几乎进行相同的转义转换,但存在一些差异。有关详细信息,请参阅%b。使用它您可以执行以下操作:

help printf

注释

  1. 使用$ ret="word1\nword2\nword3" $ cat <<EOF > tmp > HEADER > == > $(printf "%b" "$ret") > == > TRAILER > EOF $ cat tmp HEADER == word1 word2 word3 == TRAILER 函数时有一个微妙之处。 lines不断重复其格式字符串,直到它吸收其所有参数,以便格式printf每个参数之后添加换行符,包括最后一个。对于大多数用例,这正是你想要的;我对线条的大多数使用都与将结果输入到需要输入线的实用程序有关。

    但是在%s\\n的情况下,我并不真正想要尾随换行符,因为我的计划是在这里的doc中单独插入一行ret=$(lines word1 word2 word3)。幸运的是,命令替换($ret)总是从命令输出中删除尾随换行符,因此赋值后$(...)的值在参数之间有新行,但不是结束。 (这个功能偶尔会很烦人,但更多时候它正是你想要的,所以它不会引起注意。)

答案 4 :(得分:0)

使用awk '{print}'为我解决了这个问题。

cat << EOF |
line1
line2
line3
EOF
awk '{print}' > outputfile
# outputfile contents
cat outputfile
line1
line2
line3