I can define bash
functions using or omitting the function
keyword. Is there any difference?
#!/bin/bash
function foo() {
echo "foo"
}
bar() {
echo "bar"
}
foo
bar
Both calls to functions foo
and bar
succeed and I can't see any difference. So I am wondering if it is just to improve readability, or there is something that I am missing...
BTW in other shells like dash
(/bin/sh
is symlinked to dash
in debian/ubuntu) it fails when using the function
keyword.
6 Answers 6
The reason there are two different syntaxes is historical. The function
keyword came from ksh. The C-inspired ()
syntax came from the Bourne shell. POSIX standardizes only the Bourne foo ()
syntax. Bash and zsh support both, as well as the hybrid function foo () { ... }
. Except in ATT ksh, the resulting function is exactly the same.
Beware of a gotcha with the ()
syntax: the function name is subject to alias expansion.
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
In ATT ksh (but not pdksh and its descendants such as mksh), there are a few differences between functions defined by function
and functions defined with the Bourne/POSIX syntax. In functions defined by function
, the typeset
keyword declares a local variable: once the function exits, the value of the variable is reset to what it was before entering the function. With the classic syntax, variables have a global scope whether you use typeset
or not.
$ 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
Another difference in ksh is that functions defined with the function
keyword have their own trap context. Traps defined outside the function are ignored while executing the function, and fatal errors inside the function exit only the function and not from the whole script. Also, 0ドル
is the function name in a function defined by function
but the script name in a function defined with ()
.
Pdksh does not emulate ATT ksh. In pdksh, typeset
creates locally-scoped variables regardless of the function, and there are no local traps (though using function
does make some minor differences — see the man page for details).
Bash and zsh introduced the function
keyword for compatibility with ksh. However in these shells function foo { ... }
and foo () { ... }
are strictly identical, as is the bash and zsh extension function foo () { ... }
(except for potential alias expansion when parsing the definition, as explained above). The typeset
keyword always declares local variables (except with -g
of course), and traps are not local (you can get local traps in zsh by setting the local_traps
option).
-
12It should be noted that function support was added to the Korn shell before the Bourne shell introduced its
foo() command
syntax, and the Bourne syntax was later added to the Korn shell for compatibility.Stéphane Chazelas– Stéphane Chazelas2013年04月29日 11:54:48 +00:00Commented Apr 29, 2013 at 11:54 -
@StéphaneChazelas If so then is the statement This is the ksh form of function definition created to extend the Bourne and POSIX form with modified behaviors and additional features like local variables. at wiki.bash-hackers.org/scripting/obsolete wrong?Piotr Dobrogost– Piotr Dobrogost2021年10月19日 07:32:42 +00:00Commented Oct 19, 2021 at 7:32
-
@PiotrDobrogost, yes, it is wrong. The rest of that page seems also to reflect the opinion of one person (from history, looks like
@ormaaj
who's also present on this site), not the position of the bash maintainer. There are quite a few other points I don't agree with.Stéphane Chazelas– Stéphane Chazelas2021年10月22日 08:30:23 +00:00Commented Oct 22, 2021 at 8:30
There is no difference AFAIK, other than the fact that the second version is more portable.
-
47That's a BIG difference, portability... I see too many answers which simply do NOT work on (older) production systems, and also many with options that only work on linux. At least, warn that this is not the most portable way... It could be downright dangerous (asking someone to
tar cf - /some/thing | ssh user@desthost "cd destinationdir && tar xf - "
without warning them to first double-check if the version of tar on desthost will get rid of the "/" could lead to disasters in some cases...). For ex: if use afunction tar { #a safe tar with safety checks ... }
andsh
ignores it, ...Olivier Dulac– Olivier Dulac2013年04月26日 15:51:31 +00:00Commented Apr 26, 2013 at 15:51 -
2@OlivierDulac I would add that scripts that assume
sh
recognizes thefunction
keyword -- and, in general, that assume common but nonstandard features that shells likeksh
andbash
offer -- will also often not work on newer production systems, even if they worked on older releases of the same OS.bash
still providessh
on many GNU/Linux systems, but some popular distros have switched to havingsh
as a symlink todash
(the Debian Almquist SHell) to improve performance. This includes Debian and Ubuntu.Eliah Kagan– Eliah Kagan2018年04月11日 12:43:19 +00:00Commented Apr 11, 2018 at 12:43 -
8Without elaborating how exactly it's "more portable", the answer is not useful.ivan_pozdeev– ivan_pozdeev2019年03月22日 13:21:06 +00:00Commented Mar 22, 2019 at 13:21
-
4Portability is no argument nowadays where the industry is using bash or an equivalent shell in >99.9% of all environments. It boils down to readability and there is two sides: some people say "function" makes it obvious, people who learnt it from the posix standards or other shells will say braces are the more obvious style. In the end, choose one within your group or company and stick to it.Hugo G– Hugo G2019年08月26日 14:46:02 +00:00Commented Aug 26, 2019 at 14:46
foo() any-command
is the Bourne syntax supported by any Bourne-like shell but bash
, yash
and recent versions of posh
(which only support compound commands). (the Bourne shell and AT&T implementations of ksh
don't support foo() any-command > redirections
unless any-command
is a compound command though).
foo() any-compound-command
(examples of compound commands: { cmd; }
, for i do echo "$i"; done
, (cmd)
... the most commonly used being { ...; }
)
is the POSIX syntax supported by any Bourne-like shell and the one you generally want to use.
function foo { ...; }
is the Korn shell syntax, which predates the Bourne syntax. Only use this one if writing specifically for the AT&T implementation of the Korn shell and need the specific treatment it receives there. That syntax is not POSIX, but is supported by bash
, yash
and zsh
for compatibility with the Korn shell though those shells (and the pdksh
-based variants of the Korn shell) don't treat it any different from the standard syntax.
function foo () { ...; }
is the syntax of no shell and should not be used. It only happens to be supported by accident by bash
, yash
, zsh
and the pdksh
based variants of the Korn shell. Incidentally, it's also the awk
function syntax.
If we continue going down the esoteric list,
function foo() other-compound-command
(like function foo() (subshell)
or function foo() for i do; ... done
) is even worse. It is supported by bash
, yash
and zsh
, but not ksh, even the pdksh
-based variants.
While:
function foo() simple command
is only supported by zsh
.
foo bar() any-command
Or even:
$function_list() any-command
To define several functions at once is only supported by zsh
function { body; } args
() any-compound-command args
Which are anonymous function invocations, are only supported by zsh
as well.
-
5The syntax that includes both the
function
keyword and the parentheses is documented in Bash. The manual of Bash 4.2 and later says that functions are declared by the syntaxname () compound-command [ redirections ]
orfunction name [()] compound-command [ redirections ]
. In Bash 4.1.11 down to at least 3.0-beta that was just the single line[ function ] name () compound-command [redirection]
which erroneously does not cover the syntax that includes thefunction
keyword but not parentheses but does still cover the syntax that includes both thefunction
keyword and the parentheses.nisetama– nisetama2016年06月18日 06:48:54 +00:00Commented Jun 18, 2016 at 6:48 -
@nise, the point is that
bash
recognisesfunction foo {
in addition tofoo() {
for compatibility with the Korn shell (and always has) so it can interpret scripts written for the Korn shell. It does supportfunction foo () {
as well, but there's no good reason to use that one.Stéphane Chazelas– Stéphane Chazelas2016年06月20日 06:15:06 +00:00Commented Jun 20, 2016 at 6:15 -
2@StéphaneChazelas Well, I would say there is a good reason to use
function f() {
. Namely, in terms of readability, it's going to be recognized as a function by anyone who knows English and anyone who knows C, versus only one of these sets.DepressedDaniel– DepressedDaniel2016年11月25日 01:37:32 +00:00Commented Nov 25, 2016 at 1:37 -
2Should be the accepted answer. Really important
You should never combine the keyword function with the parentheses () when defining a function.
4wk_– 4wk_2018年05月07日 11:26:35 +00:00Commented May 7, 2018 at 11:26 -
3Welcome to 2019, where there is only one industry de-facto standard for linux/unix automation scripts; the one interpreter that is installed pretty much almost everywhere (exotic environments aside): bash. Write your code with all bash features, use the shebang, and you will be fine. The argument of compatibility is void.Hugo G– Hugo G2019年08月26日 14:41:56 +00:00Commented Aug 26, 2019 at 14:41
Semantically, those two forms are equivalent in Bash.
From the man page:
Shell functions are declared as follows:
name () compound-command [redirection] function name [()] compound-command [redirection]
This defines a function named
name
. The reserved word function is optional. If the function reserved word is supplied, the parentheses are optional.
EDIT: I just noticed that this question is tagged posix
. In POSIX sh
, the function
keyword is not used (though it is reserved).
Several others have answered correctly by now, but here's my concise synopsis:
The second version is portable and is likely to work with many standard (particularly POSIX) shells.
The first version will work with only bash, but you may omit the parentheses following the function name with it.
Otherwise, they represent identical entities after bash interprets them.
-
actually, the first version makes no sense except to limit it as acceptable syntax to some shells. when you include the
()
and thefunction
keyword the shell behaves as if you just didfoo(){ ...; }
anyway, except, of course, for a shell in which it is invalid syntax. and so you should dofunction foo { ...; }
if you must, orfoo(){ ...; }
otherwise.mikeserv– mikeserv2015年12月01日 08:52:35 +00:00Commented Dec 1, 2015 at 8:52
If no one else has stated it already, the form function foo() {}
, is invalid in Korn Shell (at least in KSH 93). The correct format is function foo {}
, without the double parentheses. Either format is valid in BaSH and ZSH, while ASH (and by extension DASH) does not allow function keyword at all.
-
1If you read every word, you may find that this is covered by Stéphane Chazelas’s answer (and, to a lesser extent, some of the others).Scott - Слава Україні– Scott - Слава Україні2020年03月02日 23:34:56 +00:00Commented Mar 2, 2020 at 23:34
function baz { echo "baz"; }
. See Bashism in GreyCat's wiki.