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

#!/bin/bash

function foo() {
  echo "foo"
}

bar() {
  echo "bar"
}

foo

bar


函数foobar的调用都成功了,我看不出任何区别。所以我想知道这是否只是为了提高可读性,还是我缺少某些东西...

在其他外壳中,例如dash/bin/sh与debian / ubuntu中的dash链接),它会失败当使用function关键字时。

评论

同样带或不带括号:function baz {echo“ baz”; }。请参阅GreyCat Wiki中的Bashism。

#1 楼

AFAIK没有什么区别,除了第二个版本更便于移植。

评论


那是一个巨大的差异,可移植性...我看到了太多的答案,这些答案根本不能在(较旧的)生产系统上运行,并且还有很多选项仅适用于linux。至少要警告一下,这不是最便携的方法……这可能是非常危险的(向tar cf询问某人-/ some / thing | ssh user @ desthost“ cd destinationdir && tar xf-”却没有警告他们先加倍-检查desthost上的tar版本是否会删除“ /”,在某些情况下可能导致灾难...)。例如:如果使用功能tar {#具有安全检查功能的安全tar ...}却忽略了它,...

–奥利维尔·杜拉克(Olivier Dulac)
2013年4月26日15:51



@OlivierDulac我要补充一点,假设sh可以识别function关键字的脚本-通常,假定像ksh和bash这样的shell提供的通用但非标准功能-即使在新的生产系统上也可以正常工作,在同一操作系统的旧版本上。 bash仍然在许多GNU / Linux系统上提供sh,但是一些流行的发行版已将sh用作破折号的符号链接(Debian Almquist SHell)以提高性能。这包括Debian和Ubuntu。

– Eliah Kagan
18年4月11日在12:43

如果不详细说明它的“可移植性”如何确切,答案就没有用。

– ivan_pozdeev
19 Mar 22 '19 at 13:21

如今,当行业在超过99.9%的所有环境中使用bash或等效的shell时,可移植性已不再成为争论。它归结为可读性,它有两个方面:有人说“功能”使它显而易见,从posix标准或其他shell中学习到它的人会说花括号是更明显的样式。最后,在您的小组或公司中选择一个并坚持下去。

–Hubert Grzeskowiak
19年8月26日在14:46

#2 楼

在ksh中引入了function关键字。传统的Bourne Shell仅具有foo ()语法,而POSIX仅使foo ()语法标准化。 Bourne / POSIX语法。在由function定义的函数中,function关键字声明一个局部变量:函数退出后,变量的值将重置为进入函数之前的值。使用经典语法,无论是否使用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的另一个区别是,用typeset关键字定义的函数有自己的陷阱。上下文。在执行函数时,将忽略在函数外部定义的陷阱,并且函数内部的致命错误仅会退出函数,而不会退出整个脚本。同样,functionfunction定义的函数中的函数名,但qq1202079q定义的函数中的脚本名。

Pdksh不模拟ATT ksh。在pdksh中,无论功能如何,()都会创建局部作用域变量,并且没有局部陷阱(尽管使用typeset确实会产生一些细微的差异-有关详细信息,请参见手册页。)

引入了Bash和zsh function关键字,用于与ksh兼容。但是,在这些shell中,functionfunction foo { … }严格相同,bash和zsh扩展名foo () { … }也是如此。 function foo () { … }关键字始终声明局部变量(当然,typeset除外),并且陷阱不是局部的(可以通过设置-g选项在zsh中获得局部陷阱)。

评论


应该注意的是,在Bourne shell引入其foo()命令语法之前,已将功能支持添加到Korn Shell中,并且为了兼容性,后来将Bourne语法添加到Korn Shell中。

–StéphaneChazelas
13年4月29日在11:54

#3 楼

foo() any-command
是所有类似Bourne的外壳程序所支持的Bourne语法,但bashyashposh的最新版本(仅支持复合命令)。 (尽管ksh是复合命令,但foo() any-command > redirections的Bourne shell和AT&T实现不支持any-command。)

foo() any-compound-command


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

是任何类似Bourne的外壳以及通常要使用的外壳支持的POSIX语法。

function foo { ...; }


是Korn shell语法,它早于Bourne语法。仅在专门为Korn shell的AT&T实现编写并且需要在那里接受特定处理的情况下,才使用此代码。该语法不是POSIX,但bashyashzsh支持与Korn Shell兼容,尽管这些Shell(以及基于K43 Shell的基于pdksh的变体)与标准语法没有任何区别。 />
function foo () { ...; }


是no shell的语法,不应使用。它仅偶然地由Korn外壳的基于bashyashzsh和基于pdksh的变体支持。顺便说一句,它也是awk函数的语法。

如果我们继续深入下去,

function foo() other-compound-command


(例如function foo() (subshell)function foo() for i do; ... done)会更糟。它受bashyashzsh的支持,但不支持ksh,甚至不支持基于pdksh的变体。

同时:

function foo() simple command


仅受zsh支持。

评论


Bash中记录了同时包含function关键字和括号的语法。 Bash 4.2及更高版本的手册说,函数是通过语法名()复合命令[重定向]或函数名[[)]复合命令[重定向]声明的。在Bash 4.1.11中,至少降到3.0-beta只是单行[function] name()复合命令[redirection]错误地不包括语法,该语法包括function关键字,但不包括括号,但仍然涵盖了包含function关键字和括号的语法。

– nisetama
16年6月18日在6:48

@nise,关键是bash除了foo(){还可以识别函数foo {以与Korn shell兼容(并且始终具有),因此它可以解释为Korn shell编写的脚本。它也支持函数foo(){,但是没有充分的理由使用该函数。

–StéphaneChazelas
16年6月20日在6:15

@StéphaneChazelas好,我想说有充分的理由使用函数f(){。就是说,就可读性而言,只有英语和英语的任何人都可以将它识别为一种功能,而其中只有一套。

–沮丧的丹尼尔
16年11月25日在1:37

应该是公认的答案。确实很重要定义函数时,切勿将关键字函数与括号()结合使用。

– 4wk_
18年5月7日在11:26

欢迎来到2019,那里只有一个针对Linux / unix自动化脚本的行业实际标准;几乎到处都安装了一个解释器(不包括异国环境):bash。使用所有bash功能编写代码,使用shebang,一切都会好起来的。兼容性的论点是无效的。

–Hubert Grzeskowiak
19年8月26日在14:41

#4 楼

在语义上,这两种形式在Bash中是等效的。

从手册页:


Shell函数的声明如下:

name () compound-command [redirection]
function name [()] compound-command [redirection]



这定义了一个名为name的函数。保留字功能是可选的。如果提供了函数保留字,则括号是可选的。




编辑:我只是注意到这个问题被标记为posix。在POSIX sh中,未使用function关键字(尽管它是保留关键字)。

#5 楼

到目前为止,还有其他几个人已经正确回答了,但是这是我的简要概述:第一个版本仅适用于bash,但您可以在函数名称后省略括号。

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

评论


实际上,第一个版本没有任何意义,只是将其限制为某些shell可接受的语法。当您包含()和function关键字时,shell的行为就像您刚刚做了foo(){...;无论如何,当然,对于无效语法的shell除外。所以你应该执行foo {...; }(如果必须),或者foo(){...; } 除此以外。

–mikeserv
2015年12月1日在8:52

#6 楼

如果没有人说过,则形式function foo() {}在Korn Shell中无效(至少在KSH 93中)。正确的格式是function foo {},不要带双括号。两种格式在BaSH和ZSH中均有效,而ASH(以及扩展名DASH)根本不允许使用function关键字。

评论


如果您读了每个单词,您可能会发现StéphaneChazelas的答案涵盖了这个单词(在其他程度上,也是这样)。

–斯科特
20 Mar 2 '20 at 23:34