How to use functions in Bash

Aug 08, 2023#bash

Bash functions are blocks of code within a shell script that perform specific tasks or computations. These functions offer a way to encapsulate reusable code, making scripts more organized, modular, and easier to maintain. Similar to functions in other programming languages, a Bash function takes input arguments, processes them, and may produce output results.

Function declaration

There are two ways to declare a bash function in your script. Both formats are equivalent and can be used interchangeably. The commands between the curly braces are the body of the function and can contain any valid bash commands, statements, or variables.

# Using the function name followed by parentheses
my_function () {
  echo "Bye bye!"
}

# or using the reserved word `function` followed by the function name
function my_function {
  echo "Bye bye!"
}

Function invocation

You need to define your functions before you call them in your script. To invoke a bash function, you simply use the function name as a command. You can also pass arguments to the function by adding them after the function name, separated by spaces.

# Define a function that prints hello to the given name
say_hello () {
  echo "Hello, $1!"
}

# Define a function that calculates the sum of two numbers
add_numbers () {
  local sum=$(( $1 + $2 ))
  echo "The sum of $1 and $2 is $sum."
}

# Call the functions with some arguments
say_hello John
say_hello Jane
add_numbers 3 5
add_numbers 10 20

# Output:
# Hello, John!
# Hello, Jane!
# The sum of 3 and 5 is 8.
# The sum of 10 and 20 is 30.

Function parameters

There is no explicit parameter declaration for functions because of its design and flexibility as a scripting language. Instead, they can accept arguments passed to them when called. The advantage of this approach is that it allows you to pass any number of arguments to the function without having to declare them explicitly.

While this dynamic nature of function parameters offers convenience, it also requires the developer to handle parameter validation manually if necessary.

To pass parameters to a function, you just need to write them after the function name, separated by spaces. To access the parameters inside the function, you can use the special variables $1, $2, $3, and so on up to $9. Special variable $0 represents the name of the currently executing script.

# Define a function that takes three parameters and prints them
print_params() {
  echo "Parameter 1: $1"
  echo "Parameter 2: $2"
  echo "Parameter 3: $3"
}

# Call the function and pass three parameters
print_params arg1 arg2 arg3

# Output:
# Parameter 1: arg1
# Parameter 2: arg2
# Parameter 3: arg3

However, there is a limit to how many arguments you can access this way. Bash only provides special variables from $1 to $9, which means that you can only access up to 9 arguments with this method. If you try to use $10 or higher, bash will not recognize them as arguments, but as normal variables.

You can also use the variable $# to get the number of parameters that were passed to the function. If you want to use all the parameters as a single string, you can use the variable $* or $@. These variables will expand to all the parameters separated by spaces.

print_num_params() {
  echo "Number of parameters: $#"
}

print_num_params one two three
print_num_params apple orange
# Output:
# Number of parameters: 3
# Number of parameters: 2

print_all_params() {
  echo "All parameters: $*"
}

print_all_params alpha beta gamma
# Output:
# All parameters: alpha beta gamma

Overcome the limit of 9 parameters

The limit of 9 parameters comes from historical reasons and design choices of the early Unix shells. In those early shells, the positional parameters were represented by single-character variables, such as $1, $2, and so on. As a result, only single-digit numbers were used in the variable names to represent parameters.

While the limitation of 9 parameters might seem restrictive, it’s not a significant issue in most cases since it is rare to need an excessive number of parameters for a function or script.

If you want to pass more than 9 parameters to a function, you can use the shift command to shift the parameters left by one position. This will make the second parameter become the first, the third become the second, and so on. You can then access the new first parameter with $1.

# Define a function that takes more than 9 parameters
print_all () {
  # Loop until there are no more parameters
  while [ $# -gt 0 ]; do
    # Print the first parameter
    echo "$1"
    # Shift the parameters left by one position
    shift
  done
}

# Call the function with 10 parameters
print_all A B C D E F G H I J

You can use curly braces around the parameter number to distinguish it from other characters. This will allow you to access parameters higher than 9 without confusion.

# Define a function that takes more than 9 parameters
print_some () {
  # Print the first parameter
  echo "The first parameter is $1"
  # Print the tenth parameter using curly braces
  echo "The tenth parameter is ${10}"
}

# Call the function with 10 parameters
print_some A B C D E F G H I J

You can use the special variable $@, which represents all the arguments passed to the function as an array. You can assign this variable to a new array inside the function, and then access the elements by their indices.

# Define a function that takes more than 9 parameters
print_array () {
  # Create a new array from the arguments
  local array=("$@")
  # Print the first element of the array
  echo "The first element is ${array[0]}"
  # Print the tenth element of the array using curly braces
  echo "The tenth element is ${array[9]}"
}

# Call the function with 10 parameters
print_array A B C D E F G H I J

Function variables

A global variable is a variable that can be accessed and modified anywhere in the script, regardless of the scope. You can declare a global variable by simply assigning a value to a name, without using any keyword.

A local variable is a variable that can only be accessed and modified within the function where it is declared. You can declare a local variable by using the keyword local before the name.

greet () {
  local name="Bob" # This is a local variable
  echo "Hello, $name!"
}

If you have a global and a local variable with the same name, the local variable will take precedence over the global one within the function where it is declared. However, the global variable will remain unchanged outside the function.

name="Alice"

greet () {
  local name="Bob"
  echo "Hello, $name!" # This will print "Hello, Bob!"
}

greet 
echo "Bye, $name!" # This will print "Bye, Alice!"

Function return value

You can return a value from a function by using the return command with a numerical value in the range of 0 to 255. The value will be stored in the special variable $?, which represents the exit status of the last command.

add () {
  local sum=$(( $1 + $2 )) # Add the first and second arguments
  return $sum # Return the sum as the exit status
}

add 3 5 # Call the function with two numbers
echo "The sum is $?" # Print the exit status of the function

# This will print:
# The sum is 8

If you want to return a string or an array from a function, you cannot use return, because it only accepts numerical values. Instead, you can use echo or printf to output the value to stdout, and then capture it with a command substitution.

reverse () {
  local reversed="" # Initialize an empty string
  for (( i=${#1}-1; i>=0; i-- )); do # Loop over the characters of the first argument from right to left
    reversed+="${1:i:1}" # Append each character to the reversed string
  done
  echo "$reversed" # Output the reversed string to stdout
}

name="Alice"
reversed_name="$(reverse $name)" # Capture the output of the function with command substitution
echo "$reversed_name" # Print the captured value

# This will print:
# ecilA