如何在bash脚本中向变量添加换行符


Answers:


73

bash你可以使用语法

str=$'Hello World\n===========\n'

单引号前加a $是一种新语法,该语法允许在字符串中插入转义序列。

printf内置允许将结果输出保存到变量

printf -v str 'Hello World\n===========\n'

两种解决方案都不需要子外壳。

如果在下面需要打印字符串,则应使用双引号,如以下示例所示:

echo "$str"

因为当您打印不带引号的字符串时,换行符会转换为空格。


1
语法str=$'Hello World\n===========\n'叫什么?变量替换?
zengr

5
@zengr:这就是所谓的ANSI-C报价,并且它也支持zshksh; 但是,它不兼容POSIX。
mklement0 2014年

4
@ mkelement0,它来自ksh93的,也是由zsh的,庆典,mksh和FreeBSD SH支持,将其列入POSIX的下一个主要版本是正在讨论
斯特凡Chazelas

1
似乎不能使用双引号?例如str=$"My $PET eats:\n$PET food"这种方法适用于双引号
Brad Parks

31

您可以将文字换行符放在单引号中(在任何Bourne / POSIX样式的shell中)。

str='Hello World
===========
'

对于多行字符串,此处的文档通常很方便。该字符串将作为命令的输入。

mycommand <<'EOF'
Hello World
===========
EOF

如果要将字符串存储在变量中,请cat在命令替换中使用该命令。字符串末尾的换行符将通过命令替换除去。如果要保留最后的换行符,请在末尾放置一个塞子,然后将其剥离。在POSIX兼容的外壳程序中,可以编写str=$(cat <<'EOF'); str=${str%a}适当的Heredoc,但是bash要求Heredoc出现在右括号之前。

str=$(cat <<'EOF'
Hello World
===========
a
EOF
); str=${str%a}

在ksh,bash和zsh中,可以使用$'…'引号形式在引号内扩展反斜杠转义符。

str=$'Hello World\n===========\n'

1
我正在使用GNU bash 4.1.5,并且str=$(cat <<'EOF')不能按原样工作.. )需要放在文档末尾的下一行EOF..即便如此,由于Command,它丢失了尾随的换行符替代。
Peter.O 2011年

@fred好点,我已经解释了结尾的换行符,并显示了可在bash中运行的代码。我认为这是bash中的错误,尽管老实说,在重读POSIX规范后,我发现不清楚<<当在命令替换中而在heredoc中时不是强制执行该行为。
Gilles

好东西; 为了\nbash捕获变量中的here-doc时保留尾随(和前导)实例,请考虑IFS= read -r -d '' str <<'EOF'...使用另一种停止方法(请参阅我的答案)。
mklement0 2014年

8

您是否在使用“ echo”?尝试“ echo -e”。

echo -e "Hello World\n===========\n"

2
顺便说一句。您不需要最后一个\ n,因为echo除非指定-n,否则它将自动添加一个。(但是,主要的问题是如何使这些换行符成为变量)。
Peter.O 2011年

+1在所有解决方案中,这是最直接,最简单的一种。
Hai Vu

echo -e在OS X中不起作用
Greg M. Krsak 2014年

2
@GregKrsak:在中bashecho -e 它确实可以在OS X上使用-这是因为echo它是内置的bash (而不是外部可执行文件),并且该内置也支持-e。(作为一个内置的,它应该在工作全部是bash的运行在平台上;顺便说一句,echo -e工程kshzsh太)。相比之下,然而,外部echo效用 在OS X - /bin/echo-事实上也没有支持-e
mklement0 2014年

3

如果您的脚本中多次需要换行符,则可以声明一个包含换行符的全局变量。这样,您可以在双引号字符串(可变扩展名)中使用它。

NL=$'\n'
str="Hello World${NL} and here is a variable $PATH ===========${NL}"

为什么$''需要一个子外壳?

对不起,我看错了答案。
pihentagy

我可以请那些下风的人解释一下吗?
pihentagy

真好!可以使用双引号将其包含在变量中,例如"My dog eats:${NL}dog food"
Brad Parks

3

在所有讨论中,这对我来说是最简单的方法:

bash$ str="Hello World
==========="
bash$ echo "$str"
Hello World
===========

回声命令必须使用双引号


3

为了补充现有的出色答案:

如果您正在使用bash并且更喜欢使用实际的换行符来提高可读性read则是在变量中捕获此处文档的另一种选择,该变量(与此处的其他解决方案一样)不需要使用子shell。

# Reads a here-doc, trimming leading and trailing whitespace.
# Use `IFS= read ...` to preserve it (the trailing \n, here).
read -r -d '' str <<'EOF'   # Use `IFS= read ...` to preserve the trailing \n
Hello World
===========
EOF
# Test: output the variable enclosed in "[...]", to show the value's boundaries.
$ echo "$str"
[Hello World
===========]
  • -r确保read不解释输入(默认情况下,它将对反斜杠进行特殊处理,但这很少需要)。

  • -d ''将“记录”定界符设置为空字符串,从而一次read读取整个输入(而不是单行)。

请注意,通过将$IFS(内部字段分隔符)保留为默认值$' \t\n'(空格,制表符,换行符),从分配给的值($str包括here-doc的尾随换行符)中修剪任何前导和尾随空格
(请注意,即使here-doc的正文从开始定界符(此处)之后的行开始'EOF',也不会包含前导换行符)。

通常,这是所需的行为,但是如果您确实希望该结尾的换行符,请使用IFS= read -r -d ''而不是just read -r -d '',但是请注意,然后会保留所有开头和结尾的空格。
(请注意,IFS= 直接在该read命令之前表示该赋值仅在该命令期间有效,因此无需还原先前的值。)


使用here-doc还可以让您选择使用缩进来设置多行字符串以提高可读性:

# Caveat: indentation must be actual *tab* characters - spaces won't work.
read -r -d '' str <<-'EOF' # NOTE: Only works if the indentation uses actual tab (\t) chars.
    Hello World
    ===========
EOF
# Output the variable enclosed in "[...]", to show the value's boundaries.
# Note how the leading tabs were stripped.
$ echo "$str"
[Hello World
===========]

配售-之间<<,在这里,DOC的开始分隔符('EOF'在这里)使导致制表符从这里-doc的身体,甚至关闭定界符被剥离,但千万注意,这仅与工作实际的制表符,没有空格,所以如果你的编辑器将选项卡的按键转换为空格,需要额外的工作。


-1

您需要这样做:

STR=$(echo -ne "Hello World\n===========\n")

更新:

正如Fred所指出的那样,这样您将失去尾随的“ \ n”。要分配反斜杠序列扩展的变量,请执行以下操作:

STR=$'Hello World\n===========\n\n'

让我们测试一下:

echo "[[$STR]]"

现在给我们:

[[Hello World
===========

]]

请注意,$''与$“”不同。第二个根据当前语言环境进行翻译。有关详细信息,请参见中的“引用”部分man bash


-2
#!/bin/bash

result=""

foo="FOO"
bar="BAR"

result+=$(printf '%s' "$foo")$'\n'
result+=$(printf '%s' "$bar")$'\n'

echo "$result"
printf '%s' "$result"

输出:

FOO
BAR

FOO
BAR

1
为什么不简单result+=$foo$'\n'?如果有的话,$(printf %s "$foo")将修剪尾随的换行符$foo
斯特凡Chazelas

该代码没有解释,否则对我来说还不错。
某物
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.