如何在Bash中输出多行字符串而不使用多个echo调用,类似于以下方式:
echo "usage: up [--level <n>| -n <levels>][--help][--version]"
echo
echo "Report bugs to: "
echo "up home page: "
我正在寻找一种便携的方式,只使用Bash内置工具实现。
如何在Bash中输出多行字符串而不使用多个echo调用,类似于以下方式:
echo "usage: up [--level <n>| -n <levels>][--help][--version]"
echo
echo "Report bugs to: "
echo "up home page: "
我正在寻找一种便携的方式,只使用Bash内置工具实现。
这种情况下,常常使用Here文档。
cat << EOF
usage: up [--level <n>| -n <levels>][--help][--version]
Report bugs to:
up home page:
EOF
它们在所有 Bourne 派生的 shell 中都受到支持,包括所有版本的 Bash。
cat
不是内置命令。 - Mark Reedread -d '' help <<- EOF ...
将多行字符串读入变量,然后输出了结果。 - helpermethodcat << "EOF"
。 - Joshua Pinter或者您可以这样做:
echo "usage: up [--level <n>| -n <levels>][--help][--version]
Report bugs to:
up home page: "
something
而不是被替换,请注意。 - Eric受到本页面上深思熟虑的答案的启发,我创建了一种混合方法,我认为这是最简单和最灵活的方法。你觉得呢?
首先,我将使用定义在一个变量中,这样可以在不同的上下文中重复使用。这种格式非常简单,几乎是所见即所得的,不需要添加任何控制字符。在我的看来,这似乎相当可移植(我在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}"}
echo $__usage
将会在一行上打印所有内容,而echo "$__usage"
将保留换行符。 - user1165471echo "$__usage"
中使用双引号对我很有必要,而echo $__usage
则不起作用。 - Mariocat <<EOF .... EOF
&& echo "$foo" - Jilles van Gurp使用-e
选项,然后您可以在字符串中使用\n
打印换行符。
例如:
echo -e "This will be the first line \nand this will be on the second line"
/bin/echo
在不同的操作系统中通常是不同的,也与 Bash 内置的 echo
不同。 - Dennis Williamsonecho -e
坑过...一定要使用 printf
或者带有 heredoc 的 cat
。<<-
变体的 here docs 特别好用,因为你可以在输出中去掉前导缩进,但在脚本中保留缩进以提高可读性。 - zbeekman既然我在评论中推荐了printf
,那么我应该给出一些使用示例(虽然对于打印使用信息,我更可能使用Dennis或Chris的答案)。 printf
的使用要比echo
复杂一些。它的第一个参数是格式字符串,在其中转义(如\n
)总是会被解释;它还可以包含以%
开头的格式指令,用于控制任何附加参数的包含方式和位置。以下是两种不同的方法来使用它来打印使用信息:
首先,您可以将整个消息包含在格式字符串中:
printf "usage: up [--level <n>| -n <levels>][--help][--version]\n\nReport bugs to: \nup home page: \n"
请注意,与echo
不同的是,您必须显式包含最后的换行符。此外,如果消息恰好包含任何%
字符,则必须将其写为%%
。如果您想要包括bug报告和主页地址,它们可以相当自然地添加:
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: "
通过这个选项,添加bug报告和主页地址是相当明显的:
printf "%s\n" "usage: up [--level <n>| -n <levels>][--help][--version]" "" "Report bugs to: $bugreport" "up home page: $homepage"
使用带缩进的源代码时,您可以使用<<-
(后跟破折号)来忽略前导制表符(但不包括前导空格)。
例如:
if [ some test ]; then
cat <<- xx
line1
line2
xx
fi
缩进文本并删除前导空格:
line1
line2
我通常使用内置的“read”命令,因为我认为它更加灵活和直观。它可以将一行内容读入变量,并允许与特殊的shell变量IFS相关联的单词分割。有关更多详细信息,请参阅此博客甚至手册。
read -r -d '' usage <<-EOF
usage: up [--level <n>| -n <levels>][--help][--version]
Report bugs to: $report server
up home page: $HOME
EOF
echo "$usage"
<<-
(带有减号)会忽略前导制表符,因此您可以在代码中缩进消息而不必在打印时进行缩进。 - BUFU还有一件事,使用预定义变量(这里是msg
)作为模板来使用printf
。
msg="First line %s
Second line %s
Third line %s
"
one='additional message for the first line'
two='2'
tri='this is the last one'
printf "$msg" "$one" "$two" "$tri"
这个 ^^^ 会将整个消息打印出来,而不是按照提供的顺序插入 %s
变量。
You can write your
text
freely,
in a separate:
----file.
然后
echo "$(</pathto/your_multiline_file)"
dedent() {
local -n reference="$1"
reference="$(echo "$reference" | sed 's/^[[:space:]]*//')"
}
text="this is line one
this is line two
this is line three\n"
# `text` is passed by reference and gets dedented
dedent text
printf "$text"
在不先调用dedent
的情况下输出:
this is line one
this is line two
this is line three
...并在首先调用dedent
的情况下:
this is line one
this is line two
this is line three
完整的说明,请看我之前写过的内容:
当然,感谢@Andreas Louv在此向我展示了该函数的sed
部分。
dedent
函数版本。然后,我可以将其制作成一个bash库,包含单元测试,并在需要的地方导入(源代码),就像我在这里解释的关于bash库的用法:详细示例:如何在Bash中编写、导入、使用和测试库?。那将会很酷。 - Gabriel Staples
echo >&2 ...
。 - Mark Reed--help
命令输出(应该输出到标准输出)。 - helpermethodprintf
的解决方案。尽管在echo
或cat
的基础上处于阴影之中,但它似乎要少得多。不可否认,printf
语法代表了一定的学习曲线,但我想听听其他缺点(兼容性、性能等...)。 - mjv