如何在Bash中输出多行字符串?


250

如何在Bash中输出多行字符串而不使用多个echo调用,如下所示:

echo "usage: up [--level <n>| -n <levels>][--help][--version]"
echo 
echo "Report bugs to: "
echo "up home page: "

我正在寻找一种仅使用Bash内置函数的便携式方法。


4
如果要响应错误的调用而输出使用情况消息,通常会将该消息发送给标准错误而不是标准输出,方法是echo >&2 ...
Mark Reed

2
@MarkReed通过键入输出使用情况消息--help(应该转到标准输出)。
helpermethod 2012年

对于其他人,可以获取有关“此处文档”的更多信息:tldp.org/LDP/abs/html/here-docs.html
Jeffrey Martinez,

检查printf来自Gordon Davidson 的基于解决方案。尽管处于echocat基于方法的阴影之下,但似乎没有那么多麻烦。诚然,“ printf”语法代表了一些学习曲线,但我想
听听

Answers:


296

在此,文档通常用于此目的。

cat << EOF
usage: up [--level <n>| -n <levels>][--help][--version]

Report bugs to: 
up home page:
EOF

所有Bourne派生的shell(包括所有版本的Bash)都支持它们。


4
cat是的-但不是内置的。
Mark Reed 2012年

8
@MarkReed:是的,但是它始终可用(除非在特殊情况下可能)。
暂停,直到另行通知。

6
+1 Thx。我最终使用read -d '' help <<- EOF ...将多行字符串读入变量,然后回显结果。
helpermethod 2012年

3
我可以将HEREDOC保存到变量吗?
chovy

177

或者您可以这样做:

echo "usage: up [--level <n>| -n <levels>][--help][--version]

Report bugs to: 
up home page: "

1
@OliverWeiler:它甚至可以在诸如Dash和Heirloom Bourne Shell之类的Bourne shell中使用
暂停,直到另行通知。

6
如果您在函数中需要此功能不是很好,因为您要么需要1)使字符串在整个文件的左侧一直缩排,要么2)使其缩进以与其余代码对齐,然后将其打印出来以及缩进
sg18年

43

受此页面有见地的答案的启发,我创建了一种混合方法,我认为这是最简单,更灵活的方法。你怎么看?

首先,我在变量中定义用法,这使我可以在不同的上下文中重用它。格式非常简单,几乎是所见即所得,无需添加任何控制字符。对我来说,这似乎是可移植的(我在MacOS和Ubuntu上运行了它)

__usage="
Usage: $(basename $0) [OPTIONS]

Options:
  -l, --level <n>              Something something something level
  -n, --nnnnn <levels>         Something something something n
  -h, --help                   Something something something help
  -v, --version                Something something something version
"

然后我可以简单地将其用作

echo "$__usage"

甚至更好的是,在解析参数时,我可以单行在其中回显它:

levelN=${2:?"--level: n is required!""${__usage}"}

4
这在上面的答案不起作用(未经修改)的脚本中对我有用。
大卫·韦尔奇

3
这比包含一堆字符\ t和\ n更加干净,这些字符很难在文本中找到并进行扩展以使输出与脚本中的字符串大不相同
sg

1
由于某些原因,它为我在同一行上打印了所有内容:/
Nicolas de Fontenay

2
@Nicolas:echo "$__usage"对我来说,使用双引号是必要的。echo $__usage不工作。
Mario

24

使用-e选项,然后您可以\n在字符串中打印换行符。

样品(但不确定是否是好样品

有趣的是,该-e选项虽然仍可用,但并未在MacOS的手册页中记录。它记录在Linux手册页中


6
这些手册页用于系统提供的echo命令,/bin/echo在Mac OS上没有此-e选项。当您在这些系统上使用bash时,其内置echo命令将接管。您可以通过显式键入/bin/echo whatever并观察行为差异来查看此情况。要查看内置文档,请键入help echo
Mark Reed

1
/bin/echo从一个操作系统到另一个操作系统通常都不同,并且与Bash的内置版本不同echo
暂停,直到另行通知。

@MarkReed:我稍后再试,但感谢您提供信息。+1。我将在这里留下我的答案,因为正在进行很多很好的讨论。
nhahtdh 2012年

7
echo -e不是可移植的-例如,echo的某些实现将在输出中打印“ -e”。如果您希望可移植性,请改用printf。例如,OS X 10.7.4上的/ bin / echo可以执行此操作。IIRC的bash内置回显在10.5.0下也很奇怪,但是我不再记得任何细节了。
戈登·戴维森

2
echo -e曾经咬过我...一定要使用printfcat与heredoc一起使用。<<-此处文档的变体特别好,因为您可以删除输出中的前导缩进,但可以在脚本中缩进可读性
zbeekman

22

自从我printf在评论中建议以来,我可能应该给出一些用法示例(尽管为了打印用法消息,我更可能使用Dennis或Chris的答案)。 printf使用起来比复杂得多echo。它的第一个参数是格式字符串,在其中始终会解释转义符(如\n)。它也可以包含以开头的格式指令,该格式指令可控制在何处以及如何在其中包括任何其他参数。这是将其用于使用情况消息的两种不同方法:%

首先,您可以将整个消息包含在格式字符串中:

printf "usage: up [--level <n>| -n <levels>][--help][--version]\n\nReport bugs to: \nup home page: \n"

请注意,与有所不同echo,您必须明确包括最后的换行符。另外,如果消息恰好包含任何%字符,则必须将其写为%%。如果您想包括错误报告和首页地址,可以很自然地添加它们:

printf "usage: up [--level <n>| -n <levels>][--help][--version]\n\nReport bugs to: %s\nup home page: %s\n" "$bugreport" "$homepage"

其次,您可以只使用格式字符串使它在单独的行上打印每个其他参数:

printf "%s\n" "usage: up [--level <n>| -n <levels>][--help][--version]" "" "Report bugs to: " "up home page: "

使用此选项,添加错误报告和主页地址非常明显:

printf "%s\n" "usage: up [--level <n>| -n <levels>][--help][--version]" "" "Report bugs to: $bugreport" "up home page: $homepage"

9

同样,对于缩进的源代码,您可以使用<<-(带短划线)来忽略前导制表符(但不能忽略前导空格)。例如:

if [ some test ]; then
    cat <<- xx
        line1
        line2
xx
fi

输出缩进的文本,不带前导空格:

line1
line2

那对我没有用。您正在使用什么外壳?
four43

在Ubuntu的bash 4.4.19中不起作用。它没有删除第1行和第2行之前的间距
four43,19年

1
@ four43,你是对的。无法删除前导空格。但是,请删除前导标签。因此,我从制表符和空格纠正了答案,制表符而不是空格。对不起,这个错误。我检查了手册,它显然只是说选项卡已删除。感谢您引起我的注意。
椭圆视图

0

如果使用@jorge提供的解决方案,并且发现所有内容都在同一行上,请确保将变量括在引号中:

echo $__usage

将所有内容打印在一行上,而

echo "$__usage"

将保留换行符。


这实际上是对我有用的一种解决方案。Printf可以做很多事情,而对于我的多行xml,它可能需要进行大量转义,因为它完全破坏了内容。我分配foo = cat <<EOF .... EOF&& echo“ $ foo”
吉尔斯·范古普
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.