Functions in Bash

A function in Bash (bourne-again shell)
Fig 1: A simple function in bash

In bash scripts, functions are named blocks of code that can be defined once and called multiple times within a script. They allow us to organize our code into logical units, making it easier to read, maintain, and reuse.

Defining a Function in Bash

There are two different ways to define a function in bash.

The first is using the function keyword followed by the function name and a pair of braces {} containing the function body.

function func_1() {
    # Function body
    echo "Hello from my_function"
}

When we define a function using the function keyword, parentheses following the function name (i.e. ‘func1()‘) are optional.

We can also define functions without the function keyword, using the function name followed by parentheses and braces:

my_other_function() {
    # Function body
    echo "Hello from my_other_function"
}

Calling a Function

Functions are called by using their names with or without parentheses ().

   my_function
   my_other_function()

Calling a Function With Arguments

You can pass arguments to functions just like you pass arguments to a script. Inside the function, these arguments are accessible using positional parameters ($1, $2, etc.).

greet() {
    echo "Hello, $1!"
}

greet "Alice"

Function Return Values

Functions can return values using the return statement. The return value is stored in the special variable $?.

get_sum() {
    sum=$(($1 + $2))
    return $sum
}

get_sum 5 3
echo "Sum: $?"

Local Variables

By default, variables declared inside a function are global and can be accessed outside the function:

#!/bin/bash

my_function() {
   var=123
   echo "Inside function: $var"
}  
 
my_function
echo "Outside function: $var"

Output:

Inside function: 123
Outside function: 123

However, variables declared outside of the function can be accessed from within.

We can make a variable local to the function using the local keyword (i.e. ‘local var=123’). In this case, the local variable is inaccessible outside of the function.

#!/bin/bash

my_function() {
   local var=123
   echo "Inside function: $var"
}

my_function
echo "Outside function: $var"

Output:

Inside function: 123
Outside function:

Bash doesn’t throw an error (as some languages would), but it is unable to return the value of the variable.

Similarly, if we initialize a local variable using the same name as a global variable, any local changes will not apply globally:

my_function() {
   local var=123
   echo "Inside function: $var"
}

var=456
my_function
echo "Outside function: $var"

Output:

Inside function: 123
Outside function: 456

If we remove the local keyword, the change to var inside the function is applied globally:

my_function() {
   var=123
   echo "Inside function: $var"
}

var=456
my_function
echo "Outside function: $var"

Output:

Inside function: 123
Outside function: 123

Function Position Parameters and Special Variables

In Bash, special variables are predefined variables that hold information about the environment, including command-line arguments passed to the script by the user.

Outside of any functions, the special variables $1, $2, $3… correspond with the first, second, and third command-line arguments passed to the script. But inside a function, they correspond with the arguments passed to the function.

This results in a type of shadowing, because using $1 inside the function will always return the argument passed to the function. If we want to access a command-line argument inside the function, we need to pass it to the function.

To recap: When we call a function and pass arguments to it, those arguments are assigned to the function’s positional parameters ($1, $2, etc.) within the function’s scope. This means that within the function, references to $1, $2, etc., will refer to the function’s arguments, not the script’s arguments.

However, the script’s arguments are still accessible outside the function and can be accessed using $1, $2, etc., in the outer script scope.

Here’s an example to illustrate this:

#!/bin/bash

# Function that uses its own positional parameters
my_function() {
    echo "Inside function:"
    echo "First argument: $1"
    echo "Second argument: $2"
    echo "Third argument: $3"
}

echo "Outside function:"
echo "First argument: $1"
echo "Second argument: $2"
echo "Third argument: $3"

# Call the function with arguments
my_function "foo" "bar" "baz"

# Access the script's arguments again
echo "Back outside function:"
echo "First argument: $1"
echo "Second argument: $2"
echo "Third argument: $3"

Console:

In this example, the function my_function uses its own positional parameters, but the script’s arguments remain accessible outside the function.

Other Important Notes About Functions in Bash

The following points are important to note about functions in Bash.

  • The order in which functions are defined does not matter; you can call a function before or after its definition.
  • Functions can call other functions, including themselves (this is called recursion).
  • We can also access arguments passed to the Bash script from inside a function by using the special variable $@ or $*. These variables represent all the positional parameters passed to the script, including those passed to functions.