What's the use of parentheses `()` in shell function definition?
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?
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 {
}
.
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
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.