没有
()
,语法真的会变得模棱两可。
必须有一些明确的语法来定义一个函数,而且在不大幅改变其他shell语法的情况下,它不能是这样的:
do_something {
# one or more commands go here
}
你说这个“与其当前的语法不冲突”,但实际上是有冲突的!注意,当你尝试运行那段代码的第一行时,并没有出现任何语法错误。虽然会报错,但并非语法错误。而第二行的
}
则是一个语法错误,但第一行却不是。相反,
do_something {
是在尝试运行一个名为
do_something
的命令,并将
{
作为该命令的参数传递进去。
$ do_something {
do_something: command not found
如果已经有一个名为
do_something
的命令,那么你正在运行它。如果已经有一个名为
do_something
的函数,那么你正在调用它。一般来说,语法应该是明确无歧义的,但特别重要的是,重新定义一个函数时不要意外地调用它。定义一个函数和调用一个函数的写法不应该相同。
关于shell如何处理
{
和
(
。
正如
type {
所示,
{
是一个shell关键字。这使得它类似于
[[
。如果在本应是命令的情况下使用
{
,它具有特殊的语义。具体而言,它执行命令分组。然而,在其他情况下,它可以未经转义地用作表示字面意义上的
{
字符。这包括将其作为命令的第二个或后续单词传递的情况。
当然,Bash也可以设计成与当前处理方式不同的方式来处理
{
。然而,这样的话,它的语法就不再与POSIX shell兼容,Bash也不会真正成为一个Bourne风格的shell,并且无法运行许多shell脚本。
相比之下,
(
是一个shell元字符。如果它出现在命令中并且没有被引用(使用
'
'
,
"
"
或
\
),它总是被特殊处理的。因此,在语法上没有歧义。
do_something() {
# one or more commands go here
}
那只能有一个意思。如果Bash没有函数,那么它将是一个语法错误,原因与
echo foo(bar)
一样。
如果你真的不喜欢
()
的表示方法,那么你可以使用关键字
function
并省略它,就像
sudodus提到的那样。请注意,在大多数其他Bourne风格的shell中,这不是定义函数的语法的一部分--在某些shell中,虽然支持这种方式定义函数,但其语义是
不同的--因此使用这种语法的脚本将不具备可移植性。(之所以这种语法能够明确无歧义,是因为
function
本身是Bash中的一个关键字,表示其后的内容是函数定义的开始。)
最后,请注意,虽然大多数函数定义实际上使用
{
,但任何复合命令都是允许的。如果你有一个希望始终在子shell中运行的函数体,你可以使用
(
)
而不是
{
}
。
bash
是最明显的例外),函数定义为do_something () any-command
,而在所有POSIX shell(包括bash
)中,函数定义为do_something () any-compound-command
。这里的any-command
/any-compound-command
不一定是{ command-group; }
这种复合命令,它可以是任何其他类型的复合命令,包括(subshell)
、for
/while
/if
语句或者在类似Korn的shell(包括bash
)中的[[...]]
、((...))
。 - Stéphane Chazelas