相关文章推荐

我很肯定,每个 \n 后面都没有空格,但多余的空格是怎么出来的?

5 个评论
我不确定,但是......如果你只是在同一行中输入 text="this is line one\nthis is line two\nthis is line three" ,如何?(没有任何回车)
移除每行的 \n ,你已经敲了换行键来移动到新行。
你已经给出了 \n .那么你为什么把下一行放在新的一行呢?很简单 text="this is line one\nthis is line two\nthis is line three"
去掉每行末尾的 \n ,会使输出全部在一行中运行。
啊哈。在回声行中的 "$text" 周围加上双引号是至关重要的。没有双引号,所有的换行符(包括字面的和'/n')都不能使用。有了双引号,它们都能工作。
string
bash
shell
echo
cizixs
cizixs
发布于 2014-05-29
12 个回答
alphadog
alphadog
发布于 2021-05-12
已采纳
0 人赞同

Heredoc听起来对这个目的更方便。它被用来向一个命令解释器程序发送多个命令,如 ex or

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

The string after << indi猫es where to stop.

要将这些行发送至一个文件,请使用。

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

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

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

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

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

echo "$VAR"

甚至更好的是,你可以使用缩进法使它在你的代码中更加突出。这次只要在<<后面加上-,就可以阻止标签的出现了。

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

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

why do you have <<- instead of << on the first line of the 2nd and 5th code block? does - do anything special?
@sup3rman '-' 忽略前面的制表符。 见 stackoverflow.com/questions/2500436/...
我怎样才能使读数以0的状态退出?它好像找不到行尾(因为它是-d '')而以1退出,这对你在脚本中没有帮助。
@MishaSlyusarev 使用-d '\0' 并在你的最后一行末尾添加一个 \0
Using the -d option in read -r -d '' VARIABLE <<- EOM did not work for me.
Andrew Miner
Andrew Miner
发布于 2021-05-12
0 人赞同

如果你想把字符串放入一个变量中,另一个简单的方法是这样的。

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

如果你用制表符缩进你的字符串(例如,'\t'),缩进将被剥离出来。 如果你用空格缩进,缩进将被保留。

NOTE: It is重要的是,最后的闭合括号在另一行。 替换代码1】的文字必须单独出现在一行中。

deej
这有什么意义吗?在我的mac上, ) 在同一行中也能工作。我认为这是因为在 $( ) 之间的内容会在它自己的世界里执行,而实际的命令不会看到')'。我想知道它是否也适用于其他人。
@deej From the POSIX spec : The here-document … continues until there is a line containing only the delimiter and a <newline>
deej
@Fornost 这与我所说的并不矛盾
你说实际的命令不会看到')',我同意。但是,实际的命令会看到END后面是否有换行或没有换行。Bash给了我一个警告。 here-document delimited by end-of-file .
使用时要注意 echo $USAGE echo "$USAGE" 之间的区别。
Josh Jolly
Josh Jolly
发布于 2021-05-12
0 人赞同

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
    
谢谢你解释了为什么mod在使用 "echo "命令时看到多余的空间。这个答案在bash脚本中使用时也很有效(相对于交互式shell会话而言)。我觉得这才是真正的答案,应该是一个被接受的答案。
这应该是被接受的答案。所有其他答案都提供了大量有趣的 other 解决OP的痛苦的方法,但从技术上讲,问题是 "多余的空间是如何出来的",没有人解决这个问题:-)!!! 谢谢你,乔希让-1的谜底!
Chris Maes
Chris Maes
发布于 2021-05-12
0 人赞同

在一个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
    
在Shell Scripts中,替代的技巧似乎是有效的,但对bash似乎不起作用。
@Macindows 我似乎忘记了 -e 的选项,为 echo 。请再试一次。
Mateusz Piotrowski
Mateusz Piotrowski
发布于 2021-05-12
0 人赞同

我找到了更多的解决方案,因为我想让每一行都适当缩进。

  • 您可以使用 echo

    echo    "this is line one"   \
        "\n""this is line two"   \
        "\n""this is line three" \
        > filename
    

    如果你把"\n"放在行尾的\之前,它就不起作用。

  • 另外,你可以使用 printf 以获得更好的便携性(我碰巧在使用 echo 时遇到了很多问题)。

    printf '%s\n' \
        "this is line one"   \
        "this is line two"   \
        "this is line three" \
        > filename
    
  • 然而,另一个解决方案可能是。

    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
    
  • 另一个解决方案是通过混合printfsed实现的。

    if something
        printf '%s' '
        this is line one
        this is line two
        this is line three
        ' | sed '1d;$d;s/^    //g'
    

    重组像这样格式化的代码并不容易,因为你把缩进程度硬编码到代码中。

  • 可以使用一个辅助函数和一些变量替换的技巧。

    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"
        
  • 当想独立保留代码缩进和字符串缩进时,3b是我的首选方案,至少当我不能在变量赋值中使用2时,它比3a更具可读性。 当我不在乎的时候,我只是在几行中保持引号字符串的开放。
    非常好的答案,特别是3B
    "如果你把"(n)"放在行尾的"(n)"之前,它就不起作用了。"- 是一个 大提示 when using echo.
    printf救了我,在光秃秃的docker容器中,不需要使用/n,真的很好。
    Frank-Rene Schäfer
    Frank-Rene Schäfer
    发布于 2021-05-12
    0 人赞同

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

    read -r -d '' my_variable << \
    _______________________________________________________________________________
    String1
    String2
    String3
    StringN
    _______________________________________________________________________________
    

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

    这很美。谢谢!
    Frank Bryce
    Frank Bryce
    发布于 2021-05-12
    0 人赞同

    我是来找这个答案的,但也想用管道连接到另一个命令。 给出的答案是正确的,但如果有人想用管道连接,你需要在多行字符串之前用管道连接,如图所示

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

    这将允许你有一个多行字符串,但也可以把它放在后续命令的stdin中。

    Gabriel Staples
    Gabriel Staples
    发布于 2021-05-12
    0 人赞同

    Hard to read:

    This 看起来太像巴什了 :)(难以阅读),不符合我的一般口味。

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

    Better, easier-to-read:

    让我们搞点更有Pythonic风格的东西(这仍然是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() function which I use here.

    下面是神奇的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
    

    变量text被传递给dedentby reference因此,被修改的内容inside该函数影响变量outside the function.

    更多细节和解释以及参考资料,请看我在这里的另一个答案。相当于bash中python的textwrap dedent

    Problem with your original attempt

    OP的引文(重点是我加的)。

    我确定每个\n后面都没有空格,但多余的空间是怎么出来的?

    你最初的尝试是这样的。

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

    ...但你的输出在第二和第三行前有一个额外的空格。为什么?

    通过推理和实验,我的结论是:echo可以转换行末的实际换行(当你实际按了Enter) 进入一个空间.因此,该空格显示在刚才的行前之后文中的每个\n

    因此,解决办法是在每一行的结尾处用反斜杠\来转义真正的换行,在你的字符串的引号内的任何一行的结尾,像这样。

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

    请不要把空格填上before那些尾部的反斜线(如:text="this is line one\n \),否则这些空格会直接回到你的输出中,并导致你出现同样的问题,即多余的空格

    或者,就用我上面的dedent函数的技术,它还有一个额外的功能,就是能够用你的代码缩进,看起来非常漂亮,很有可读性。

    Beni Trainor
    Beni Trainor
    发布于 2021-05-12
    0 人赞同

    有许多方法可以做到这一点。对我来说,用管道将缩进的字符串输送到 sed works nicely.

    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的答案,但要细化一些。

    luk
    luk
    发布于 2021-05-12
    0 人赞同

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

    AA='first line
    \nsecond line 
    \nthird line'
    echo $AA
    output:
    first line
    second line
    third line
        
    it3xl
    it3xl
    发布于 2021-05-12
    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" 
    

    You'll get something like this

    所有前导和结尾的空白将被保留下来,以备不时之需。

    echo "$v3" > filename
        
    ish-west
    ish-west
    发布于 2021-05-12
    0 人赞同

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

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

    同样的,但使用一个变数。

    #!/bin/sh
    text="$(sed 's/^[[:blank:]]*//' << whatever
        this is line one
        this is line two
        this is line three
    
     
    推荐文章