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 thefunction
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*}
abcMake substitutions similar to
sed
$ var="abcde"; echo ${var/de/12}
abc12Use a default value
$ default="hello"; unset var; echo ${var:-$default}
helloand 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
How to Increase the /Proc/Pid/Cmdline 4096 Byte Limit
What Makes a Kernel/Os Real-Time
How to Use Awk to Convert All the Lower-Case Letters into Upper-Case
Can Gdb Change the Assembly Code of a Running Program
"Make" Command for Windows - Possible Options
Rename File Command in Unix with Timestamp
Cross Compile from Linux to Arm-Elf (Arm926Ej-S/Mt7108)
Return Code When Os Kills Your Process
Possible Values for 'Uname -M'
How to Program for Linux's New 'Fanotify' File System Monitoring Feature
What Is the Purpose of Features.H Header
How to Create Tar for Files Older Than 7 Days Using Linux Shell Scripting
Why Does Gcc Force Pic for X64 Shared Libs
Sort by Third Column Leaving First and Second Column Intact in Linux