What Are the Parentheses Used for in a Bash Shell Script Function Definition Like "F () {}"? Is It Different Than Using the "Function" Keyword

What are the parentheses used for in a bash shell script function definition like f () {} ? Is it different than using the function keyword?

The keyword function has been deprecated in favor of function_name() for portability with the POSIX spec

A function is a user-defined name that
is used as a simple command to call a
compound command with new positional
parameters. A function is defined with
a "function definition command".

The format of a function definition
command is as follows:

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

Note that the { } are not mandatory so if you're not going to use the keyword function (and you shouldn't) then the () are necessary so the parser knows you're defining a function.

Example, this is a legal function definition and invocation:

$ myfunc() for arg; do echo "$arg"; done; myfunc foo bar
foo
bar

What is the purpose of () in a bash function?

The function keyword is a bash extension. The standard syntax for function definitions is simply:

name() { body }

and the parentheses are needed to recognize that this is a function definition rather than an ordinary command invocation. They're not used to contain parameters, they just distinguish the syntax.

bash added the function keyword at the beginning. When you use this, the parentheses are optional, so you can write

function example_f { echo "$var1" ; echo "$var2" ; }

Why bash functions use round brackets, if those are never filled with arguments?

Parentheses are optional. From Bash Reference Manual --> 3.3 Shell Functions:

Functions are declared using this syntax:

name () compound-command [ redirections ]

or

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

This defines a shell function named name. The reserved word function
is optional. If the function reserved word is supplied, the
parentheses are optional
. The body of the function is the compound
command compound-command (see Compound Commands). That command is
usually a list enclosed between { and }, but may be any compound
command listed above. compound-command is executed whenever name is
specified as the name of a command. When the shell is in POSIX mode
(see Bash POSIX Mode), name may not be the same as one of the special
builtins (see Special Builtins). Any redirections (see Redirections)
associated with the shell function are performed when the function is
executed.

So these are equivalent:

function hello {
echo "hello there"
}

hello () {
echo "hello there"
}

In Bash, functions can access global variables normally, so that the approach is slightly different from other languages. Normally, there is no need to use return because there is no value to catch.

See an example. Here, we have a global variable myvar containing a value. In the functions mytest and mytest_inner we are changing its value. However, in one case the value affects the global environment, whereas in the other does not.

In mytest we change the value and it affects the main block. In mytest_inner we do the same, but the value is just changed locally, in the sub-shell running in the function.

#!/bin/bash

function mytest {
echo "mytest -> myvar: $myvar"
((myvar++))
}

function mytest_inner () {
(
echo "mytest_inner -> myvar: $myvar"
((myvar++))
)
}

myvar=$1
mytest
echo "main -> myvar: $myvar"
mytest_inner
echo "main -> myvar: $myvar"

Let's run it:

$ ./myscript.sh 20
mytest -> myvar: 20
main -> myvar: 21
mytest_inner -> myvar: 21
main -> myvar: 21

How to use double or single brackets, parentheses, curly braces

In Bash, test and [ are shell builtins.

The double bracket, which is a shell keyword, enables additional functionality. For example, you can use && and || instead of -a and -o and there's a regular expression matching operator =~.

Also, in a simple test, double square brackets seem to evaluate quite a lot quicker than single ones.

$ time for ((i=0; i<10000000; i++)); do [[ "$i" = 1000 ]]; done

real 0m24.548s
user 0m24.337s
sys 0m0.036s
$ time for ((i=0; i<10000000; i++)); do [ "$i" = 1000 ]; done

real 0m33.478s
user 0m33.478s
sys 0m0.000s

The braces, in addition to delimiting a variable name are used for parameter expansion so you can do things like:

  • Truncate the contents of a variable

    $ var="abcde"; echo ${var%d*}
    abc
  • Make substitutions similar to sed

    $ var="abcde"; echo ${var/de/12}
    abc12
  • Use a default value

    $ default="hello"; unset var; echo ${var:-$default}
    hello
  • and several more

Also, brace expansions create lists of strings which are typically iterated over in loops:

$ echo f{oo,ee,a}d
food feed fad

$ mv error.log{,.OLD}
(error.log is renamed to error.log.OLD because the brace expression
expands to "mv error.log error.log.OLD")

$ for num in {000..2}; do echo "$num"; done
000
001
002

$ echo {00..8..2}
00 02 04 06 08

$ echo {D..T..4}
D H L P T

Note that the leading zero and increment features weren't available before Bash 4.

Thanks to gboffi for reminding me about brace expansions.

Double parentheses are used for arithmetic operations:

((a++))

((meaning = 42))

for ((i=0; i<10; i++))

echo $((a + b + (14 * c)))

and they enable you to omit the dollar signs on integer and array variables and include spaces around operators for readability.

Single brackets are also used for array indices:

array[4]="hello"

element=${array[index]}

Curly brace are required for (most/all?) array references on the right hand side.

ephemient's comment reminded me that parentheses are also used for subshells. And that they are used to create arrays.

array=(1 2 3)
echo ${array[1]}
2

I want to take in using the user's input, then call a function using a case statement

There's no need for the () behind saveToLog:

#!/bin/bash

read -n1 -p "Save to log? [y,n] " choice \n
case $choice in
y|Y) saveToLog ;;
n|N) echo "no" ;;
*) echo "dont know" ;;
esac

function saveToLog(){
echo "Saving to log"
}

Will call saveToLog on y|Y


Note: saveToLog must be delared as it is (using the function keyword) for this to work. Please take a look at this Stackoverflow question for more information about function and ()

Difference between single and double square brackets in Bash

Single [] are posix shell compliant condition tests.

Double [[]] are an extension to the standard [] and are supported by bash and other shells (e.g. zsh, ksh). They support extra operations (as well as the standard posix operations). For example: || instead of -o and regex matching with =~. A fuller list of differences can be found in the bash manual section on conditional constructs.

Use [] whenever you want your script to be portable across shells. Use [[]] if you want conditional expressions not supported by [] and don't need to be portable.

Are double square brackets [[ ]] preferable over single square brackets [ ] in Bash?

[[ has fewer surprises and is generally safer to use. But it is not portable - POSIX doesn't specify what it does and only some shells support it (beside bash, I heard ksh supports it too). For example, you can do

[[ -e $b ]]

to test whether a file exists. But with [, you have to quote $b, because it splits the argument and expands things like "a*" (where [[ takes it literally). That has also to do with how [ can be an external program and receives its argument just normally like every other program (although it can also be a builtin, but then it still has not this special handling).

[[ also has some other nice features, like regular expression matching with =~ along with operators like they are known in C-like languages. Here is a good page about it: What is the difference between test, [ and [[ ? and Bash Tests



Related Topics



Leave a reply



Submit