Sage-Code Laboratory
index<--

Bash Functions

Bash functions are names given to specific group of commands. This group can be enclosed in squigly braces { ... } or round branchets ( ... ). Functions can have input parameters, output and result status. Let's study the details in this article.

Declare Function

You can declare functions in scripts using keyword "function" or just a function identifier follow by empty round brackets like this: name () { ... }. Unlike other languages, you can't define parameters in brackets, these are allways empty.

functions.sh
# define two functions
sum () (
  echo $(( $1 + $2 ))
)

function exp {
  echo $(( $1 ** $2 )); return 0
}

Node: In this example, I have define 2 functions with 2 different methods. Each function can receive 2 parameters. There is no "return" keyword in first function. These functions have otuput the result using statement "echo" and this is how you create the actual function result in Bash. Using "return" statement you can signal "0" if the function terminate normaly or "1" or any number > 1 that signal an error.

Function Call

In Python you use round brackets to call a function by like this: name() and this is logic, but in Bash it is all different. You do not use round brackets for enclosing the arguments. Instead, you must enumerate the arguments separated by space. Let's study the example below:

external.sh
#!/bin/bash
#iport external functions
source ./functions.sh

# call sum and exp 4 times
# we capture the output, then
# display the result using echo

for x in {1..4}
do
  s=$(sum $x 2);
  echo "sum($x,2) = $s"
  e=$(exp $x 2); 
  echo "exp($x,2) = $e"
  echo
done
Console
~/bash-repl$ bash external.sh
sum(1,2) = 3
exp(1,2) = 1

sum(2,2) = 4
exp(2,2) = 4

sum(3,2) = 5
exp(3,2) = 9

sum(4,2) = 6
exp(4,2) = 16

~/bash-repl$ 

Note: In previous exampke we import this script: "functions.sh". The functions defined in this script become available in "external.sh" and we can call them as if they would be localy defined. The session global space is loading the functions and make them accesible. No qualifier is necesary to call these functions. They become part of the common execution space.

Exit Status

Bash is crashing when something goes wrong. We can define smarter functions that return a status so we can handle eventual errors. Doing this can improve your code quality and avoid catastrophic defects. Let's analyze the example:

return.sh
#!/bin/bash
# a function that return result
function div {
   if (( $2 == 0 )); then
      return 1
   fi
   echo $(($1 / $2)); return 0
}
echo "enter 2 numbers"
read -p "a=" a
read -p "b=" b

# call and capture result using $?
d=$(div $a $b)
# error checking
if [ $? -gt 0 ]; then
   echo "division by 0 not supported"
   exit 1
else
   echo "$a / $b = $d"
   exit 0
fi

This example is available for you to open and run on your own computer. I have run this example 2 times in the console. Here is the result as expected. However you will probaly notice, there are no fractions. Bash do not have suport for float nunbers.

console
~/bash-repl$ bash return.sh
enter 2 numbers
a=16
b=2
16 / 2 = 8
~/bash-repl$ bash return.sh
enter 2 numbers
a=6
b=0
division by 0 not supported

Download the example from here: GitHub

Recursive Functions

This may be unexpected but Bash does support recursive functions. This is a function that call itself with different arguments. The number of calls is limited by the memory size of the computer and if you are not careful you can create infitinte recursive calls. Let's analyze a classic exampe:

factorial.sh
#recursive function
function factorial {
  local n=$1
  local r=1
  if (( $n > 1 )) 
  then
     r=$(( $n * $(factorial $(($n - 1)) ) ))
  fi
  echo $r; return 0
}
#use parameter
if [ $# == 0 ]; then
   echo "use: faxtorial.sh x "
   exit 1
fi
echo $(factorial $1)
console
~/bash-repl$ bash  hello.sh
~/bash-repl$ bash factorial.sh 0
1
~/bash-repl$ bash factorial.sh 1
1
~/bash-repl$ bash factorial.sh 4
24
~/bash-repl$ bash factorial.sh 8
40320
~/bash-repl$ bash factorial.sh 10
3628800
~/bash-repl$ bash factorial.sh 20
2432902008176640000
~/bash-repl$ 

Accessing Parameters

You have already notice the notation $1 is reading value of first parameter and $2 the second. But what about $0 this is returning the name of current script. The same notation is used for calling a script. Script and functions can both have parameters and they are using the same notation.

Total number of parameters can be read using this notation $#, and can be used to verify if the function has received several parameters. There is one more thing. Large number of parameters > 9 must be read by using this notation: ${nn} where nn is a group of 2 or more digits. It is also safe to use notation ${n}.

Nested Functions

Bash has suport for local functions. These are function defined inside other functions. I have created a demo code that works. Let's read this code and learn some advanced Bash functionality.


Read next: Regular Expressions