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

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之后没有空间,但额外的空间是如何出来的?


当前回答

难读:

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

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函数,它还具有能够与代码一起缩进的附加功能,使其看起来非常漂亮、漂亮和可读。

其他回答

如果你把它放在下面,它就会工作:

AA='first line
\nsecond line 
\nthird line'
echo $AA
output:
first line
second line
third line

我发现了更多的解决方案,因为我想有每一行适当缩进:

You may use echo: echo "this is line one" \ "\n""this is line two" \ "\n""this is line three" \ > filename It does not work if you put "\n" just before \ on the end of a line. Alternatively, you can use printf for better portability (I happened to have a lot of problems with echo): printf '%s\n' \ "this is line one" \ "this is line two" \ "this is line three" \ > filename Yet another solution might be: text='' text="${text}this is line one\n" text="${text}this is line two\n" text="${text}this is line three\n" printf "%b" "$text" > filename or text='' text+="this is line one\n" text+="this is line two\n" text+="this is line three\n" printf "%b" "$text" > filename Another solution is achieved by mixing printf and sed. if something then printf '%s' ' this is line one this is line two this is line three ' | sed '1d;$d;s/^ //g' fi It is not easy to refactor code formatted like this as you hardcode the indentation level into the code. It is possible to use a helper function and some variable substitution tricks: unset text _() { text="${text}${text+ }${*}"; } # That's an empty line which demonstrates the reasoning behind # the usage of "+" instead of ":+" in the variable substitution # above. _ "" _ "this is line one" _ "this is line two" _ "this is line three" unset -f _ printf '%s' "$text"

我听到这个答案,但也想把它输送到另一个命令。给出的答案是正确的,但如果有人想要管道它,您需要在像这样的多行字符串之前管道它

echo | tee /tmp/pipetest << EndOfMessage
This is line 1.
This is line 2.
Line 3.
EndOfMessage

这将允许您拥有多行字符串,但也可以将其放在后续命令的stdin中。

下面是我喜欢的方式来分配一个多行字符串的变量(我认为它看起来不错)。

read -r -d '' my_variable << \
_______________________________________________________________________________

String1
String2
String3
...
StringN
_______________________________________________________________________________

在这两种情况下,下划线的数量是相同的(这里是80)。

难读:

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

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函数,它还具有能够与代码一起缩进的附加功能,使其看起来非常漂亮、漂亮和可读。