102

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.

  • 8
    Also with or without the parenthesis: function baz { echo "baz"; }. See Bashism in GreyCat's wiki. – manatwork Apr 26 '13 at 11:34
45

There is no difference AFAIK, other than the fact that the second version is more portable.

  • 32
    That'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 a function tar { #a safe tar with safety checks ... } and sh ignores it, ... – Olivier Dulac Apr 26 '13 at 15:51
  • 1
    @OlivierDulac I would add that scripts that assume sh recognizes the function keyword -- and, in general, that assume common but nonstandard features that shells like ksh and bash offer -- will also often not work on newer production systems, even if they worked on older releases of the same OS. bash still provides sh on many GNU/Linux systems, but some popular distros have switched to having sh as a symlink to dash (the Debian Almquist SHell) to improve performance. This includes Debian and Ubuntu. – Eliah Kagan Apr 11 '18 at 12:43
  • 3
    Without elaborating how exactly it's "more portable", the answer is not useful. – ivan_pozdeev Mar 22 '19 at 13:21
  • Portability 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. – Hubert Grzeskowiak Aug 26 '19 at 14:46
99

The function keyword was introduced in ksh. The traditional Bourne shell only had the foo () syntax, and POSIX standardizes only the foo () syntax.

In ATT ksh (but not pdksh), 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 () { … }. 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).

  • 8
    It 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 Apr 29 '13 at 11:54
  • 2
    Is it correct that function { ... }; f; omits f after the function keyword? – Ruslan Jun 14 '16 at 16:34
34
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.

  • 1
    The 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 syntax name () compound-command [ redirections ] or function 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 the function keyword but not parentheses but does still cover the syntax that includes both the function keyword and the parentheses. – nisetama Jun 18 '16 at 6:48
  • @nise, the point is that bash recognises function foo { in addition to foo() { for compatibility with the Korn shell (and always has) so it can interpret scripts written for the Korn shell. It does support function foo () { as well, but there's no good reason to use that one. – Stéphane Chazelas Jun 20 '16 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 Nov 25 '16 at 1:37
  • 2
    Should be the accepted answer. Really important You should never combine the keyword function with the parentheses () when defining a function. – 4wk_ May 7 '18 at 11:26
  • Welcome 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. – Hubert Grzeskowiak Aug 26 '19 at 14:41
22

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).

3

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 the function keyword the shell behaves as if you just did foo(){ ...; } anyway, except, of course, for a shell in which it is invalid syntax. and so you should do function foo { ...; } if you must, or foo(){ ...; } otherwise. – mikeserv Dec 1 '15 at 8:52

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.