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

时间:2014-05-29 08:44:39

标签: string bash shell echo

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

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

11 个答案:

答案 0 :(得分:501)

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

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

答案 1 :(得分:117)

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

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

如果您使用制表符缩进字符串(即&#39; \ t&#39;),则会删除缩进。如果缩进空格,缩进将保留。

注意: 显着,最后一个右括号在另一行。 END文字必须单独显示在一行上。

答案 2 :(得分: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

答案 3 :(得分:35)

在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

答案 4 :(得分:31)

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

  1. 您可以使用echo

    echo    "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"
    

答案 5 :(得分:2)

我来听是在寻找这个答案,但也想将其传递给另一个命令。给定的答案是正确的,但如果有人要传送它,则需要像这样在多行字符串之前传送它

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

这将使您拥有多行字符串,但也可以将其放在后续命令的标准输入中。

答案 6 :(得分:1)

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

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

String1
String2
String3
...
StringN
_______________________________________________________________________________

两种情况下的下划线数目相同(此处为80)。

答案 7 :(得分:1)

如果您将其放置如下,它将起作用:

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

答案 8 :(得分:0)

仅提及简单的单行连接,因为有时它会很有用。

# 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

答案 9 :(得分:0)

有很多方法可以做到这一点。对我而言,将缩进的字符串管道输送到 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 的答案,但略有改进。

答案 10 :(得分:0)

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

#!/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

;-)