21

A function is defined as:

do_something () {
    do it
}

I could understand its name 'do_something' and the curly bracket to encapsulate the actions code, but am unable to get the idea what's the purpose of () here, since there are no named parameters in Bash scripts. It might be better and straightforward to define it as

do_something {
  do it
}

Which does not conflict with its current syntax, and even more declares that there are no named parameters. What's the usage of () here?

45

Without the (), the syntax really would be ambiguous.

There has to be some unambiguous syntax for defining a function, and without substantially altering other shell syntax, it cannot be this:

do_something {
    # one or more commands go here
}

You said this "does not confict with its current syntax," but it does! Notice that you do not get any kind of syntax error when you try to run the first line of that. You get an error, but it is not an error about syntax. The second line, with }, is a syntax error, but the first line is not. Instead, do_something { attempts to run a command called do_something and pass { as an argument to that command:

$ do_something {
do_something: command not found

If there is already a command called do_something, you are running it. If there is already a function called do_something, you are calling it. It's important in general that syntax be unambiguous, but it is also important specifically that it be possible to redefine a function without accidentally calling it instead. Defining a function and calling it should not look the same.

How the shell treats { and (.

As type { will tell you, { is a shell keyword. This makes it like [[. If used in a situation where it would otherwise be a command, { carries special semantics. Specifically, it performs command grouping. In other situations, however, it may be used unescaped to denote a literal { character. This includes the situation of passing it as a second or subsequent word of a command.

Of course, Bash could have been designed to treat { differently than it currently does. However, its syntax would then no longer have been compatible with the POSIX shell, and Bash would not really be a Bourne-style shell and would not be capable of running many shell scripts.

In contrast, ( is a shell metacharacter. It is always treated specially if it appears in a command and is not quoted (with ' ', " ", or \). There is thus no ambiguity in the syntax:

do_something() {
    # one or more commands go here
}

That couldn't mean anything else. If Bash didn't have functions, then it would be a syntax error, for the same reason echo foo(bar) is a syntax error.

If you really dislike the () notation then you can use the keyword function and omit it, as sudodus mentions. Note that this is not part of the syntax for defining functions in most other Bourne-style shells--and in some, it is supported but functions defined that way have different semantics--and so a script that uses it will not be portable. (The reason this syntax is able to be unambiguous is that function is itself a keyword in Bash that signifies that whatever follows it is the start of a function definition.)

Finally, note that while most function definitions use { in practice, any compound command is permitted. If you had a function whose body you wanted always to run in a subshell, you could use ( ) rather than { }.

| improve this answer | |
  • 1
    At a higher level, it's about human expectations and readability. In most languages, particularly in C, fortran, and others common around the time the bash scripting languages was developed, a function/subroutine always has an argument list, possibly empty, that's enclosed in parentheses. Change that paradigm, and you make it harder to understand the language. – jamesqf Apr 11 '18 at 18:52
15

The () token is to tell the shell interpreter that you are declaring a function.

$ do_something () { echo 'do it'; } ; do_something
do it

An alternative in bash is function

function do_something {
 echo 'do it'
}

or as a one-liner you can test

$ bash -c "function do_something { echo 'do it'; } ; do_something"
do it
| improve this answer | |
  • 2
    The function keyword is a pre-POSIX ksh-ism that bash supports for backwards compatibility; however, bash supports it badly (not making variables function-local default, as old ksh did in functions declared in that form). Consequently, it's not ideal for new code. See wiki.bash-hackers.org/scripting/obsolete – Charles Duffy Apr 11 '18 at 20:14
  • @CharlesDuffy, Thanks for this explanation :-) – sudodus Apr 11 '18 at 20:26
  • 1
    @CharlesDuffy Are you saying ksh and bash accept some syntax that makes a variable local in ksh but global in bash? That doesn't sound right. My understanding, based partly on that post and checking (in ksh93), is that ksh makes variables local in fewer situations than bash, never more. In bash, typeset without -g in a function always declares a local variable. With the function keyword, bash and ksh scope variables the same way, do they not? – Eliah Kagan Apr 12 '18 at 0:23
  • @EliahKagan I think what Charles has been referring to has been demonstrated in Gille's answer here – Sergiy Kolodyazhnyy Jan 7 '19 at 14:40
9

How very one-true-brace-style-ist of you!

Consider other, perfectly fine brace styles:

foo
{
  ...
}
foo
  {
    ...
  }
foo
  while ...; do ...; done # Look, ma! No braces!
foo
( ... ) # Look, ma! No braces and a subshell to boot!

How can the shell tell that those are function definitions and not simply a command foo followed by command lists? In all these cases, an additional disambiguating factor, like () or the function keyword is necessary.

| improve this answer | |
  • On second thought, that's not actually OTBS, since the one place where OTBS allows braces on a new line is for function definitions. – muru Apr 11 '18 at 8:59
  • 4
    I think there's an argument to be made that you were right to characterize it as OTBS, because unlike functions in C and C++, a function definition in a Bourne-style shell script can be nested directly in the body of another function definition and so arguably doesn't deserve to be distinguished. (Or maybe this is the style popular in Java programming where methods get their opening brace on the same line, rather than OTBS.) Either way, you make an excellent point about how the syntax would have to impose tight constraints on brace placement to work at all without () or something like it. – Eliah Kagan Apr 11 '18 at 9:08

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.