带有额外空间的多行字符串(保留缩进)

问题描述 投票:294回答:7

我想使用以下内容将一些预定义的文本写入文件:

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

string bash shell echo
7个回答
513
投票

为此,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

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


121
投票

如果您正在尝试将字符串转换为变量,另一种简单的方法是这样的:

USAGE=$(cat <<-END
    This is line one.
    This is line two.
    This is line three.
END
)

如果使用制表符缩进字符串(即“\ t”),则缩进将被删除。如果缩进空格,缩进将保留。

注意:最后一个右括号在另一行上很重要。 END文本必须单独出现在一行上。


67
投票

echo在传递给它的参数之间添加空格。 $text受变量扩展和单词拆分的影响,因此你的echo命令相当于:

echo -e "this" "is" "line" "one\n" "this" "is" "line" "two\n"  ...

你可以看到在“this”之前会添加一个空格。您可以删除换行符,并引用$text以保留换行符:

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

echo "$text" > filename

或者你可以使用printf,它比echo更强大和便携:

printf "%s\n" "this is line one" "this is line two" "this is line three" > filename

在支持大括号扩展的bash中,您甚至可以:

printf "%s\n" "this is line "{one,two,three} > filename

36
投票

在bash脚本中,以下工作:

#!/bin/sh

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

或者:

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

cat filename给出:

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

31
投票

我找到了更多解决方案,因为我想让每一行都正确缩进:

  1. 你可以使用echoecho "this is line one" \ "\n""this is line two" \ "\n""this is line three" \ > filename 如果你把"\n"放在\之前的行尾就不行了。
  2. 或者,您可以使用printf以获得更好的可移植性(我碰巧在echo上遇到了很多问题): printf '%s\n' \ "this is line one" \ "this is line two" \ "this is line three" \ > filename
  3. 另一个解决方案可能是: 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 要么 text='' text+="this is line one\n" text+="this is line two\n" text+="this is line three\n" printf "%b" "$text" > filename
  4. 通过混合printfsed实现另一种解决方案。 if something then printf '%s' ' this is line one this is line two this is line three ' | sed '1d;$d;s/^ //g' fi 在将缩进级别硬编码到代码中时,重构像这样格式化的代码并不容易。
  5. 可以使用辅助函数和一些变量替换技巧: 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"

1
投票

以下是我为变量分配多行字符串的首选方法(我觉得它看起来不错)。

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

String1
String2
String3
...
StringN
_______________________________________________________________________________

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


1
投票

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

AA='first line
\nsecond line 
\nthird line'
echo $AA
output:
first line
second line
third line
© www.soinside.com 2019 - 2024. All rights reserved.