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

Jie*_*eng 103 bash quoting

当我做

str="Hello World\n===========\n"
Run Code Online (Sandbox Code Playgroud)

\n也打印出来了 那我怎么会有换行符呢?

enz*_*tib 119

bash你可以使用语法

str=$'Hello World\n===========\n'
Run Code Online (Sandbox Code Playgroud)

以 a 开头的单引号$是一种允许在字符串中插入转义序列的新语法。

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

printf -v str 'Hello World\n===========\n'
Run Code Online (Sandbox Code Playgroud)

这两种解决方案都不需要子shell。

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

echo "$str"
Run Code Online (Sandbox Code Playgroud)

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

  • @zengr:它被称为 [ANSI-C 引用](http://www.gnu.org/software/bash/manual/bash.html#ANSI_002dC-Quoting),并且在 `zsh` 和 `ksh` 中也支持它;但是,它不符合 POSIX 标准。 (10认同)
  • @mkelement0,它来自ksh93,也被zsh、bash、mksh和FreeBSD sh支持,它在POSIX的下一个主要修订版中的包含正在[讨论中](http://austingroupbugs.net/view.php?id) =249) (6认同)
  • 双引号似乎不起作用?例如 `str=$"我的 $PET 吃:\n$PET 食物"` ? [这种方法](https://unix.stackexchange.com/a/106456/22734)适用于双引号 (4认同)
  • `str=$'Hello World\n============\n'` 的语法是什么?变量替换? (2认同)

Gil*_*il' 38

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

str='Hello World
===========
'
Run Code Online (Sandbox Code Playgroud)

对于多行字符串,这里的文档通常很方便。该字符串作为命令的输入提供。

mycommand <<'EOF'
Hello World
===========
EOF
Run Code Online (Sandbox Code Playgroud)

如果要将字符串存储在变量中,请cat在命令替换中使用该命令。字符串末尾的换行符将被命令替换删除。如果您想保留最后的换行符,请在末尾放置一个塞子,然后将其剥离。在符合 POSIX 的 shell 中,您可以编写str=$(cat <<'EOF'); str=${str%a}后跟适当的 heredoc,但 bash 要求 heredoc 出现在右括号之前。

str=$(cat <<'EOF'
Hello World
===========
a
EOF
); str=${str%a}
Run Code Online (Sandbox Code Playgroud)

在 ksh、bash 和 zsh 中,您可以使用带$'…'引号的形式在引号内展开反斜杠转义。

str=$'Hello World\n===========\n'
Run Code Online (Sandbox Code Playgroud)

  • 我正在使用 GNU bash 4.1.5,并且 `str=$(cat &lt;&lt;'EOF')` 不能按原样工作。`)` 需要放在结束后的下一行-doc `EOF`.. 但即便如此,它也会由于命令替换而丢失尾随换行符。 (2认同)

pih*_*agy 14

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

NL=$'\n'
str="Hello World${NL} and here is a variable $PATH ===========${NL}"
Run Code Online (Sandbox Code Playgroud)


Mik*_*ike 10

你在使用“回声”吗?试试“echo -e”。

echo -e "Hello World\n===========\n"
Run Code Online (Sandbox Code Playgroud)

  • 顺便提一句。您不需要最后的 \n,因为除非您指定 -n,否则 `echo` 会自动添加一个。(但是,问题的主要问题是如何将这些换行符放入变量中)。 (2认同)
  • @GregKrsak:在`bash` 中,`echo -e` _does_ 可以在OS X 上运行——这是因为`echo` 是一个bash _builtin_(而不是外部可执行文件),并且内置函数确实支持`-e`。(作为内置函数,它应该适用于 bash 运行的 _all_ 平台;顺便说一句,`echo -e` 也适用于 `ksh` 和 `zsh`)。然而,相比之下,OS X 上的 _external `echo` 实用程序_ - `/bin/echo` - 确实_不_支持 `-e`。 (2认同)

mkl*_*nt0 6

为了补充现有的优秀答案:

如果您正在使用bash并且更喜欢使用实际的换行符来提高可读性read则是在变量中捕获 here-doc 的另一种选择,它(与此处的其他解决方案一样)不需要使用子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
Run Code Online (Sandbox Code Playgroud)
# Test: output the variable enclosed in "[...]", to show the value's boundaries.
$ echo "$str"
[Hello World
===========]
Run Code Online (Sandbox Code Playgroud)
  • -r确保read不解释输入(默认情况下,它会特殊对待反斜杠,但很少需要)。

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

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

通常,这是所需的行为,但如果您确实想要该尾随换行符,请使用IFS= read -r -d ''而不仅仅是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
Run Code Online (Sandbox Code Playgroud)
# Output the variable enclosed in "[...]", to show the value's boundaries.
# Note how the leading tabs were stripped.
$ echo "$str"
[Hello World
===========]
Run Code Online (Sandbox Code Playgroud)

-<<here-doc 分隔符 ( 'EOF', here )之间放置和开始分隔符会导致前导制表符从 here-doc 正文甚至结束分隔符中剥离,但请注意,这仅适用于实际制表符,而不适用于空格,因此如果您编辑器将 Tab 键转换为空格,需要额外的工作。


小智 5

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

bash$ str="Hello World
==========="
bash$ echo "$str"
Hello World
===========
Run Code Online (Sandbox Code Playgroud)

回声命令必须使用双引号