9

This script demonstrates defining a bash function with parenthesis verses with braces. The parenthesis have the nice effect of making environment variables created in the function "local", I guess because the function body is executed as a sub-shell. The output is:

A=something
A=
B=something
B=something

The question is if this is allowed syntax for defining a function.

#!/bin/bash

foo() (
    export A=something
    echo A=$A
)

bar() {
    export B=something
    echo B=$B
}

foo
echo A=$A
bar
echo B=$B
Dude Bro
  • 1,152
  • 1
  • 10
  • 13
ELO
  • 319
  • 1
  • 3
  • 4
  • wrong guess. These variables appear to be local, because this [compound command](http://wiki.bash-hackers.org/syntax/basicgrammar#compound_commands) is executed in a separate group (context), NOT a subshell!! – Florian Apr 30 '15 at 09:41
  • @Florian Bash and POSIX call it a "subshell environment", maybe that's what he meant. But true: not a new process. – Ciro Santilli OurBigBook.com Jul 09 '15 at 11:13

2 Answers2

11

Yes, that syntax is allowed. As described in the bash man page, the definition of a bash function is:

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

Some more description (also from the man page):

The body of the function is the compound command compound-command. That command is usually a list of commands between { and }, but may be any command listed under Compound Commands above.

() and {} enclosed lists are compound commands. The full list (again from the man page, just edited down to a simple list):

A compound command is one of the following:

(list)
{ list; }
((expression))
[[expression]]
for name [ in word ] ; do list ; done
for (( expr1 ; expr2 ; expr3 )) ; do list ; done
select name [ in word ] ; do list ; done
case word in [ [(] pattern [ | pattern ] ... ) list ;; ] ... esac
if list; then list; [ elif list; then list; ] ... [ else list; ] fi
while list; do list; done
until list; do list; done
activedecay
  • 10,129
  • 5
  • 47
  • 71
Carl Norum
  • 219,201
  • 40
  • 422
  • 469
  • Thanks for that. I notice this fails: foo() ( export A=something ; echo A=$A ) bar() { export B=something ; echo B=$B } This works: foo() ( export A=something ; echo A=$A ; ) bar() { export B=something ; echo B=$B ; } Yet so does this: ( echo Hi ; echo Bye ) – ELO Feb 01 '13 at 18:06
  • 1
    Sorry, I'm not sure I understand - are you asking something about the semicolons? – Carl Norum Feb 01 '13 at 18:15
  • For examples, see also the Code-Golf FAQ answer about defining functions using `f()(CODE)` instead of `f(){ CODE;}` [Tips for golfing in Bash](https://codegolf.stackexchange.com/a/41201). – Peter Cordes Sep 24 '18 at 07:07
4

Both are valid, and as Carl mentioned any compound command can also be used, e.g.:

$ f() if [ "$1" = 'a' ]; then echo 'equals a'; fi
$ f a
equals a
$ f b
$

POSIX 7 2.9.5 Function Definition Command http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_09_05:

The format of a function definition command is as follows:

fname() compound-command[io-redirect ...]

[...] The argument compound-command represents a compound command, as described in Compound Commands.

Then 2.9.4 Compound Commands http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_09_04:

(compound-list) [...] Variable assignments and built-in commands that affect the environment shall not remain in effect after the list finishes.

{ compound-list;} Execute compound-list in the current process environment.

The semantics are the same as using () without a function definition: it does not create a new process, but gets executed in what POSIX and Bash call a "subshell environment".

Community
  • 1
  • 1
Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985