“function foo() {}”和“foo() {}”之间的区别

“function foo() {}”和“foo() {}”之间的区别

我可以bash使用或省略function关键字来定义函数。有什么区别吗?

#!/bin/bash

function foo() {
  echo "foo"
}

bar() {
  echo "bar"
}

foo

bar

对函数的调用都foo成功bar了,我看不出有什么区别。所以我想知道这是否只是为了提高可读性,或者我缺少什么......

顺便说一句,在其他 shell 中,例如dash(在 debian/ubuntu 中/bin/sh符号链接dash),使用关键字时会失败function

答案1

存在两种不同语法的原因是历史性的。关键词function来自克什。受 C 启发的()语法来自伯恩外壳POSIX仅标准化 Bournefoo ()语法。 Bash 和 zsh 支持两者,以及混合function foo () { … }.除了 ATT ksh 之外,生成的函数完全相同。

请注意语法中的陷阱():函数名称受别名扩展的影响。

alias f=g
f () { echo foo; }
type f               # f is an alias for g
type g               # g is a shell function
f                    # alias f → function g → print foo
\f                   # no alias lookup → f: not found
g                    # function g

function在 ATT ksh(但不是 pdksh 及其后代,例如 mksh)中,由 Bourne/POSIX 语法定义的函数和用 Bourne/POSIX 语法定义的函数之间存在一些差异。在由 定义的函数中function,该typeset关键字声明一个局部变量:一旦函数退出,该变量的值将重置为进入该函数之前的值。使用经典语法,无论您使用typeset与否,变量都具有全局作用域。

$ ksh -c 'a=global; f () { typeset a=local; }; f; echo $a'
local
$ ksh -c 'a=global; function f { typeset a=local; }; f; echo $a'
global

ksh 中的另一个区别是使用function关键字定义的函数有自己的陷阱上下文。执行函数时,函数外部定义的陷阱将被忽略,函数内部的致命错误仅退出该函数,而不退出整个脚本。另外,$0是由 定义的函数中的函数名称,function但是由 定义的函数中的脚本名称()

Pdksh 不模拟 ATT ksh。在 pdksh 中,typeset无论函数如何,都会创建本地范围的变量,并且没有本地陷阱(尽管使用function确实会产生一些细微的差异 - 有关详细信息,请参阅手册页)。

Bash 和 zsh 引入了function与 ksh 兼容的关键字。然而,在这些 shell 中function foo { … }, 和foo () { … }是严格相同的,bash 和 zsh 扩展也是如此function foo () { … }(解析定义时潜在的别名扩展除外,如上所述)。关键字typeset总是声明局部变量(-g当然除了 with ),陷阱不是局部的(你可以通过设置选项在 zsh 中获得局部陷阱local_traps)。

答案2

据我所知,除了第二个版本更便携之外,没有什么区别。

答案3

foo() any-command

是任何类似 Bourne 的 shell 支持的 Bourne 语法,但是bashyash和最新版本posh(仅支持复合命令)。 (Bourne shell 和 AT&T 实现ksh不支持foo() any-command > redirections除非any-command是复合命令)。

foo() any-compound-command

(复合命令的示例:{ cmd; }, for i do echo "$i"; done, (cmd)... 最常用的是{ ...; }

是任何类似 Bourne 的 shell 都支持的 POSIX 语法,也是您通常想要使用的语法。

function foo { ...; }

是 Korn shell 语法,它早于 Bourne 语法。仅当专门为 Korn shell 的 AT&T 实现编写并且需要它在那里接受的特定处理时才使用此选项。该语法不是 POSIX,但受bashyashzshKorn shell 支持,尽管这些 shell(以及pdkshKorn shell 的基于 - 的变体)不会将其视为与标准语法有任何不同。

function foo () { ...; }

的语法是壳和不应该使用。它只是偶然被bashyash和Korn shell 的基础变体zsh支持。pdksh顺便说一句,这也是awk函数语法。

如果我们继续深入深奥的清单,

function foo() other-compound-command

(如function foo() (subshell)function foo() for i do; ... done)更糟糕。bashyash和都支持它zsh,但 ksh 不支持它,甚至pdksh基于 - 的变体也是如此。

尽管:

function foo() simple command

仅支持zsh.

foo bar() any-command

甚至:

$function_list() any-command

一次定义多个函数仅支持zsh

function { body; } args
() any-compound-command args

哪个是匿名函数调用,仅支持zshas well。

答案4

到目前为止,其他几个人已经正确回答了,但这是我的简要概要:

第二个版本是可移植的,并且可能与许多标准(特别是 POSIX)shell 一起使用。

第一个版本仅适用于 bash,但您可以省略函数名称后面的括号。

否则,在 bash 解释它们之后,它们代表相同的实体。

相关内容