shell函数定义中括号`()`的用法是什么?

函数定义为:

do_something () { do it } 

我可以理解它的名字’do_something’和大括号来封装动作代码,但我无法理解这里的()目的是什么,因为Bash脚本中没有命名参数。 将其定义为可能更好,更直接

 do_something { do it } 

这与其当前语法不冲突,甚至更多声明没有命名参数。 ()的用法是什么?

没有() ,语法真的很模糊。

必须有一些明确的语法来定义一个函数,并且在没有实质上改变其他 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中定义函数的语法的一部分 – 在某些情况下,它受支持但是以这种方式定义的函数具有不同的语义 – 因此使用它的脚本将不可移植。 (这种语法能够明确的原因是function本身就是Bash中的一个关键字,表示其后面的任何内容都是函数定义的开头。)

最后,请注意,虽然大多数函数定义使用{实际上,但允许使用任何复合命令。 如果你有一个你希望总是在子shell中运行的函数,你可以使用( )而不是{ }

()令牌是告诉shell解释器你声明一个函数。

 $ do_something () { echo 'do it'; } ; do_something do it 

bash的另一种选择是function

 function do_something { echo 'do it' } 

或作为一个单行,你可以测试

 $ bash -c "function do_something { echo 'do it'; } ; do_something" do it 

你是多么的真正支撑式的主义者!

考虑其他完美的支撑样式:

 foo { ... } foo { ... } foo while ...; do ...; done # Look, ma! No braces! foo ( ... ) # Look, ma! No braces and a subshell to boot! 

shell如何告诉那些是函数定义而不仅仅是命令foo后跟命令列表? 在所有这些情况下,需要一个额外的歧义因素,如()function关键字。