Bash \heredoc中的变量n

Bash \heredoc中的变量n,bash,variables,escaping,heredoc,Bash,Variables,Escaping,Heredoc,有没有办法让Bash herdoc在herdoc中解释“\n\”呢 我在循环中有一个迭代构建的字符串,类似于 for i in word1 word2 word3 do TMP_VAR=$i ret="$ret\n$TMP_VAR" done 然后我想在一个herdoc中使用创建的字符串: cat <<EOF > myfile HEADER == $ret == TRAILER EOF 而不是 HEADER == \nword1\nword2

有没有办法让Bash herdoc在herdoc中解释“\n\”呢

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

for i in word1 word2 word3
do
        TMP_VAR=$i
        ret="$ret\n$TMP_VAR"
done
然后我想在一个herdoc中使用创建的字符串:

cat <<EOF > myfile
HEADER
==
$ret
==
TRAILER
EOF
而不是

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

可能吗?或者我是否应该以其他方式构建初始字符串?

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

ret="$ret"$'\n'"$TMP_VAR"
ret+=$'\n'"$TMP_VAR"
您还可以使用
+=
附加到字符串:

ret="$ret"$'\n'"$TMP_VAR"
ret+=$'\n'"$TMP_VAR"
正如其他人(以及其他问题的其他答案)所说,您可以将编码字符放入字符串中,以便shell进行解释

x=$'\n' # newline
printf -v x '\n' # newline
也就是说,我不相信有任何方法可以直接将编码的新行放入一个heredoc


没有什么特别的,
最好的解决方案是用实际的换行符构建变量,而不是插入需要用换行符替换的字符序列

我发现下面的函数非常有用,因此我将它放在bash启动文件中;对于您这个简单的案例,它将完美地工作:

lines() { printf %s\\n "$@"; }
有了这些,你可以写:

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

但是,如果出于任何原因,您确实希望使用转义序列而不是实际字符来构造字符串,则可以使用bash
printf
内置的扩展功能进行扩展,即
%b
格式代码<代码>%b
执行几乎相同的转义转换,但有几个不同之处。有关详细信息,请参见帮助打印f。使用该选项,您可以执行以下操作:

$ ret="word1\nword2\nword3"
$ cat <<EOF > tmp
> HEADER
> ==
> $(printf "%b" "$ret")
> ==
> TRAILER
> EOF
$ cat tmp
HEADER
==
word1
word2
word3
==
TRAILER
$ret=“word1\nword2\nword3”
$cat头
> ==
>$(printf“%b”$ret)
> ==
>拖车
>EOF
$cat tmp
标题
==
字1
字2
字3
==
拖车
笔记
  • 使用
    函数有一个微妙之处
    printf
    不断重复其格式字符串,直到它吸收所有参数,这样格式
    %s\\n
    会在每个参数(包括最后一个参数)后加一个换行符。对于大多数用例,这正是您想要的;我对行的大多数使用都与将结果输入一个实用程序有关,该实用程序需要输入行

    但是在
    ret=$(lines-word1-word2-word3)
    的情况下,我并不真的想要后面的换行符,因为我的计划是在here文档中的一行上单独插入
    $ret
    。幸运的是,命令替换(
    $(…)
    )总是从命令的输出中删除尾随的换行符,因此赋值后的
    ret
    值在参数之间有换行符,但不在末尾。(此功能有时会让人恼火,但更常见的情况是,它正是您想要的,因此不会引起注意。)

  • 更改:

    ==
    $ret
    ==
    
    致:


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

    cat输出文件
    #输出文件内容
    cat输出文件
    第1行
    第2行
    第3行
    
    可能的重复我不确定在herdeoc中有一个编码的换行符会有什么价值,我也不认为这是直接可能的,但它不是真正的重复。AFAICT以前没有人专门要求使用heredoc换行符。如果您可以确定某个特定字符永远不会出现在您的heredoc中,例如
    |
    ,您可以将其替换为
    cat Yes!非常感谢。我忘了我可以使用命令替换!顺便说一句,你也可以使用“echo-e”,效果与printf“%b”相同。@KamilRoman:实际上,你需要
    echo-en
    ,但这是一个次要的问题
    printf
    更加灵活。(特别是格式自动重复功能。)但是
    echo-e
    printf%b
    都不是标准的,所以它们都不是便携式的。
    ret=$(lines word1 word2 word3)
    
    $ ret="word1\nword2\nword3"
    $ cat <<EOF > tmp
    > HEADER
    > ==
    > $(printf "%b" "$ret")
    > ==
    > TRAILER
    > EOF
    $ cat tmp
    HEADER
    ==
    word1
    word2
    word3
    ==
    TRAILER
    
    ==
    $ret
    ==
    
    ==
    $(echo -e $ret)
    ==