我想写一些预定义的文本与以下文件:

text="this is line one\n
this is line two\n
this is line three"

echo -e $text > filename

我期待的是这样的:

this is line one
this is line two
this is line three

但我明白了:

this is line one
 this is line two
 this is line three

我确信在每个\n之后没有空间,但额外的空间是如何出来的?


当前回答

或者用空格保持文本缩进:

#!/bin/sh

sed 's/^[[:blank:]]*//' >filename <<EOF
    this is line one
    this is line two
    this is line three
EOF

相同但使用变量:

#!/bin/sh

text="$(sed 's/^[[:blank:]]*//' << whatever
    this is line one
    this is line two
    this is line three
)"

echo "$text" > filename

;-)

其他回答

这里只提一个简单的单行连接,因为它有时很有用。

# for bash

v=" guga "$'\n'"   puga "

# Just for an example.
v2="bar "$'\n'"   foo "$'\n'"$v"

# Let's simplify the previous version of $v2.
n=$'\n'
v3="bar ${n}   foo ${n}$v"

echo "$v3" 

你会得到这样的结果

bar 
   foo 
 guga 
   puga 

所有前导和结尾空格将被保留

echo "$v3" > filename

有很多方法可以做到这一点。对我来说,将缩进的字符串输送到sed中效果很好。

printf_strip_indent() {
   printf "%s" "$1" | sed "s/^\s*//g" 
}

printf_strip_indent "this is line one
this is line two
this is line three" > "file.txt"

这个答案是基于Mateusz Piotrowski的回答,但做了一些改进。

难读:

这看起来太像了:)(很难读懂)对我的一般口味来说:

cat << EndOfMessage
This is line 1.
This is line 2.
Line 3.
EndOfMessage

更好,更容易阅读:

让我们找一些更python化的东西(这仍然是bash):

text="this is line one
      this is line two
      this is line three\n"
dedent text
printf "$text"             # print to screen
printf "$text" > file.txt  # print to a file

啊…这是更好的。:)这让我想起了我在这里使用的Python的textwrap.dedent()函数。

下面是这个神奇的dedent函数的样子:

dedent() {
    local -n reference="$1"
    reference="$(echo "$reference" | sed 's/^[[:space:]]*//')"
}

示例输出到屏幕:

this is line one
this is line two
this is line three

如果不先调用dedent text ',输出将如下所示:

this is line one
      this is line two
      this is line three

变量文本通过引用传递给dedent,因此在函数内部修改的内容会影响函数外部的变量。

有关更多细节、解释和参考资料,请参阅我在这里的另一个回答:相当于python在bash中的textwrap dedent

你最初的尝试有问题

OP的引用(加上我的强调):

我确信在每个\n之后没有空间,但额外的空间是如何出来的?

你最初的想法是这样的:

text="this is line one\n
this is line two\n
this is line three"
echo -e $text

...但是你的输出在第2行和第3行之前有一个额外的空间。为什么?

通过推理和实验,我的结论是echo将行尾的实际换行符(实际按Enter时得到的换行符)转换为空格。因此,空格显示在文本中每个\n之后的行前。

因此,解决方案是在每一行的末尾转义真正的换行符,方法是在字符串的引号内的任何一行的末尾加一个反斜杠\,就像这样:

text="this is line one\n\
this is line two\n\
this is line three"

echo -e "$text"

不要在后面的反斜杠前加空格(比如:text="这是第一行\n \),否则这个空格会直接回到你的输出中,导致你在额外的空格上遇到同样的问题!

或者,只需使用我的技术与上面的dedent函数,它还具有能够与代码一起缩进的附加功能,使其看起来非常漂亮、漂亮和可读。

在bash脚本中,以下工作:

#!/bin/sh

text="this is line one\nthis is line two\nthis is line three"
echo -e $text > filename

另外:

text="this is line one
this is line two
this is line three"
echo "$text" > filename

Cat文件名给出:

this is line one
this is line two
this is line three

对于这个目的,Heredoc听起来更方便。它用于向命令解释器程序(如ex或cat)发送多个命令

cat << EndOfMessage
This is line 1.
This is line 2.
Line 3.
EndOfMessage

<<后面的字符串表示停止的位置。

要将这些行发送到文件,请使用:

cat > $FILE <<- EOM
Line 1.
Line 2.
EOM

你也可以将这些行存储到一个变量中:

read -r -d '' VAR << EOM
This is line 1.
This is line 2.
Line 3.
EOM

这将行存储到名为VAR的变量中。

打印时,请记住变量周围的引号,否则将看不到换行符。

echo "$VAR"

更好的是,您可以使用缩进使它在代码中更加突出。这一次,只需在<<后添加一个-来阻止选项卡出现。

read -r -d '' VAR <<- EOM
    This is line 1.
    This is line 2.
    Line 3.
EOM

但是在代码中必须使用制表符而不是空格来缩进。