Bash Function Usage Guide for Absolute Beginners

New to bash or shell scripting? Let's start learning. Bash scripting can be considered the first step to learn programming languages. You may be in any IT stream but there will come a point in your career where you will end up writing your first shell script. So let us start learning about, how we can define bash function?

I have written this tutorial considering absolute beginners who have just started with shell scripting. For experience users, you may skip the lecture.

 

What is a function in bash?

  • The definition of function will not change only for bash and will remain same across all programming languages
  • Although there may be few functional changes so we will only talk about shell function
  • A function can be considered as command which internally is a combination of multiple commands, values, positional parameters etc
  • So we club all these values, commands together into a single function so it becomes easier for us to use the same set of commands together

Confused? Why do I need to use function?

Let us take a simple example. We have to perform below set of tasks
1. Create 100 Users
2. Assign different password to individual users
3. Make sure the user changes password on it's first login
4. Assign separate home directory for the user

  • We have a bunch of tasks to be done
  • We can go ahead and write individual commands for each tasks, OR
  • We define a function and put all the commands, variables into this one single function (or you may create more than one function)
  • Using this single function we would be able to perform all the tasks
  • Still wondering why we need a function for this, why not just call it in plain script?
  • Yes TRUE, we can call these commands in plain script but imagine you have 10000+ lines of code, wouldn't it be easier if we had it arranged in separate function where each function does it's own job

For example:
1. One function to create users and assign passwords
2. Another one to handle it's home directories
3. Last one to make sure user changes it's password after first login

This is all very theoretical, I will show you some real time practical examples to help you understand better.

 

How do we define bash function?

The basic syntax to define a function in shell script would be

<function_name> [()] {
	compound-command 
}

OR you can also use

function <function_name> [()] {

	compound-command 
}

 

What is the difference between these function syntax?

You must be wondering which of these syntax should I choose to write my first function?

The one liner answer is that "you can use any of the above syntax" but I would recommend to also read below:

The detailed answer is:

  • function keyword is originally used with KSH shell
  • Later bash shell also introduced support for function keyword
  • There is no reason to use parenthesis while defining a function, although bash man page does mentions about using parenthesis with function
  • But we never know as the support for () may be removed in future bash version
  • So the recommended syntax for shell script with global support would be
function <function_name> {

	compound-command 
	[redirection]
}

To learn more about the different syntax and their behaviour you can read more at Unix Stack Exchange

 

Understanding the function syntax

  • You define your bash function name by replacing function_name in the syntax
  • There is no such restriction while choosing for function name. It can contain solely letters, numbers, and underscores, and beginning with a letter or underscore.
  • The block between curly braces {} is the main function block where you will place your commands
  • Unlike some of the programming language, there is no such restriction to put semi-colon ";" after every command
  • But if you plan to write two different command in same line then you must use semi-colon ";", for example, command 1; command 2
# cat /tmp/shell_script.sh
  1 #!/bin/bash
  2
  3 function print_name {
  4   echo "My name is Deepak"
  5 }
  6
  7 # Call your function
  8 print_name
  • In Line 3 we have defined our function print_name and starting of our function block with OPEN curly brace {
  • Line 4 contains the command to be executed inside the function body
  • Line 5 contains the CLOSE curly braces }
  • On Line 8 we will call our function by just writing the function name. No special handling needed

This function will only execute echo "My name is Deepak" on the terminal screen, the output from this script:

# /tmp/shell_script.sh
My name is Deepak

You must provide executable permission to this script chmod u+x /tmp/shell_script.sh

 

Local and Global variables

Now since you know about bash function, you should be really careful the way you would define your VARIABLES

Why do I need VARIABLES in script?

  • It is strongly recommended to use VARIABLES as much as possible while writing any script
  • As it avoids writing hard code and repetitive values
  • Let's assume you have to use a file from /tmp/dir1/ file at different location in your script which you define manually without using variables
  • Now few days later you realise that the path needs to be changed to /tmp/dir2/file, now imagine doing this task at all the places within the script and if you miss to update even at one place then the script would fail
  • So we create one variable with name name such as FILE_PATH=/tmp/dir1/file and I will use this variable $FILE_PATH across the script. Now even if you have to change the path you just update this one variable and you are good to do go..

It is important you understand the difference between Local and Global Variable. Let us look at this sample script:

  1 #!/bin/bash
  2
  3 SOME_VAR="GLOBAL"
  4
  5 function print_name {
  6   SOME_VAR="LOCAL"
  7   echo "My name is Deepak"
  8 }
  9
 10 # Check the value of VARIABLE before we call the function
 11 echo "Before calling function, SOME_VAR: $SOME_VAR"
 12
 13 # Call your function
 14 print_name
 15
 16 # Check the value of VARIABLE after we call the function
 17 echo "After calling function, SOME_VAR: $SOME_VAR"

The output from this script:

Before calling function, SOME_VAR: GLOBAL
My name is Deepak
After calling function, SOME_VAR: LOCAL

What do we understand?

  • Line 3 we have defined SOME_VAR which will be our global variable
  • Line 6 we have re-defined SOME_VAR inside the function print_name block, since this is limited to the function block, it will be considered as local variable
  • Line 11 we check the value of SOME_VAR. At this stage since the function print_name is not executed yet, so the content of SOME_VAR would be "GLOBAL"
  • Line 14 we execute the function which would also execute the SOME_VAR variable within the function block
  • In Line 17 we re-check the content of SOME_VAR and now it will be changed to LOCAL because the function print_name has now made this as global variable
  • So after Line 14, any command or function if tries to use SOME_VAR then the value of this variable would be LOCAL

 

Call bash function with arguments

  • We also have an option to pass input arguments to the bash function.
  • Why would you need that you ask?
  • Imagine you are trying to write a function to compare two integers but these integers will be provided by end user as command line argument
  • So how will function access these integer values for comparison?
  • We can pass them as an input to the script which will further be passed to the function
  • To pass values within the script you should pass the values just next to the function separated by single white space character

The syntax to for this would be:

function_name "[arg1]" "[arg2]" "[arg3]" ..

To store this you should also collect these input values within your function. You can use any variable name, I have used ARG1, ARG2, ARG3 here..

function function_name {
   ARG1="$1"
   ARG2="$2"
   ARG3="$3"
   
   COMMANDS
}

Or you can pass all the input values into single array/variable

function_name string1 string2 string3

To store this you should also collect these input values within your function into a single array/variable

function function_name {
   ARG="$@"
   
   COMMANDS
}

 

Pass and store input arguments into different Variables

In this sample shell script, I have passed three input strings to my bash function pass_arg
And I am storing these three strings into three different variables and then printing the content of this variable. It is recommended to put all the input values into inverted commas " " assuming anyone of these input values contains white space.

#!/bin/bash

function pass_arg {
  # Collect Input Values
  ARG1="$1"
  ARG2="$2"
  ARG3="$3"

  # Print the variable content
  echo "First: $ARG1"
  echo "Second: $ARG2"
  echo "Third: $ARG3"
}
# Executing the function
pass_arg "argument1" "argument2" "argument3"

From the output from this script we see the script was successfully able to store all the three input values into three different variables:

First: argument1
Second: argument2
Third: argument3

 

Pass and store input arguments into single Variable

In the next sample shell script, I will store all the input values into single VARIABLE. In this case you should not use inverted commas " " for individual strings or else only the first value "string1" would be considered by the bash function. Either you put the entire list of strings under inverted commas like "string1 string2 string3" or you can just pass the entire list without inverted commas to your function as I have done in this script.

function pass_arg {
  # Collect Input Values
  ARG="$@"

  # Print the variable content
  echo "Input argument list: $ARG"
  echo "Variable Length: ${#ARG[@]}"

}

# Call your function
pass_arg string1 string2 string3

From the output from this scrip we see the function has successfully parsed the input list of values and stored into single variable. I have also printed the variable length so that we know the script has not considered it as an array.

Input argument list: string1 string2 string3
Variable Length: 1

Even though there are 3 strings each separated by white space, bash considers it as a VARIABLE

 

Pass and store input arguments into Array

To store the input values as ARRAY you must make sure of two things
1. Do not pass input values under semi colon
2. Store the input values within bash function inside parenthesis

I would recommend to also read How to split string into array using 4 simple methods in bash

#!/bin/bash
function pass_arg {
  # Collect Input Argument and convert the VAR to ARRAY using parenthesis
  ARG=("$@")

  # Print the array content
  echo "Input argument list: $ARG"
  echo "Variable Length: ${#ARG[@]}"

}

# Call your function
pass_arg string1 string2 string3

The output from this script:

Input argument list: string1 string2 string3
Variable Length: 3

Now bash considers ARG as ARRAY as it could identify three different strings from ARG from the length syntax.

 

Let me also give you one practical example on this:

In shell scripts we normally have a lot of echo statement and most of the time we have to also store these echo statements to some log files
So we create a function which will echo statement to the screen and also send the same message to a log file so that we don't have to repeat the same command twice:

#!/bin/bash

# Define Log file variable
LOGFILE=/var/log/myapp.log

function log_content {

   # print on output
   echo "$*"
   
   # store the logs
   echo "$*" >> $LOFILE

}

# Execute the function
log_content "Starting the process"

We can also enhance the function to print date and time along with hostname while storing the logs in the log file just like the format as we have messages in /var/log/messages

#!/bin/bash

# Define Log file variable
LOGFILE=/var/log/myapp.log

function log_content {

   # print on output
   echo "$*"
   
   # store the logs with timestamp
   echo "`date +"%b %e %T"` `hostname` "$*" >> LOGFILE

}

# Execute the function
log_content "Starting the process"

So now we have a function which taken input values and then use it to print the info on screen and also store it in log file.

 

Collect command line arguments from end user and pass it to function

  • You can also collect input from end user as command line argument and then pass it as an input to the function
  • We are storing the input values into single variable i.e. ARG
  • Then we are passing this variable to the function
  • Next inside the function we need to again collect and store it in a different variable INPUT_ARG for further processing
  • Now you can use INPUT_ARG within your function
#!/bin/bash

ARG="$*"

function pass_arg {

  INPUT_ARG="$1"
  echo "Input Argument: $INPUT_ARG"
}

# Call your function
pass_arg "$ARG"

Then we execute the script with an input value as "deepak"

# /tmp/shell_script.sh deepak
Input Argument: deepak

The function has collected the input value, stored it in ARG then this $ARG was passed on to the function. The function read this input and stored it in INPUT_ARG which was later used as $INPUT_ARG.

 

Use Return Values in Function

  • When working with bash functions, you must be familiar with return keyword used inside function
  • You cannot use return outside function block
  • In laymen terms, return is used as an alternate for exit statement. (Although both are not same)
  • The advantage with return is that you can choose to come out of a function without actually coming out of the script.
  • If you have already heard of continue, break as I explained in my earlier articles with for and while loop then you may get confuse with return as it may sound familiar
  • continue and break are used to come out of the loop conditions only but the additional advantage with return is to pass an exit code also while coming out of the loop

Let us use this in shell script to understand the usage properly:

  • Line 3 we have defined a function return_value
  • Line 5 we are printing a simple statement on the screen using echo
  • Line 6-10 we are check the exit status of echo command
  • At Line 7 if the exit status is 0 then return 0 will be called
  • If the exit status in non-zero then at Line 9, return 1 would be called
  • At Line 13 we have defined another echo statement within the same function block
  • NOW the mistake which I have done is that I have also put an echo after the return value. This section will never be called, so look out for such scenarios.
  • Please NOTE If your loop triggers return value then the remaining part of the function will not be executed
  • Line 18 we execute the function and again at Line 19 we check the exist status of the function
  • Line 21 we print a statement with the exit code of the function. This exit code should match the return code from within the function block
  1 #!/bin/bash
  2
  3 function return_values {
  4
  5   echo "We do something"
  6   if [ $? == 0 ];then
  7      return 0
  8   else
  9      return 1
 10   fi
 11
 12   # This will not be called as the function will exit at return stage above
 13   echo "Good Day"
 14
 15 }
 16
 17 # Call your function
 18 return_values
 19 exit_status=$?
 20
 21 echo "The exit status of function is: $exit_status"

Now we execute the script, the exit code of our script is same as function's return value

We do something
The exit status of function is: 0

We know we did some mistakes in the above script, The proper way to write above script would be:

#!/bin/bash

function return_values {

  echo "We do something"
  if [ $? != 0 ];then
     return 1
  fi

  # This will not be called as the function will exit at return stage above
  echo "Good Day"
  return 0
}

# Call your function
return_values
exit_status=$?

echo "The exit status of function is: $exit_status"

So now we don't exit at the first command instead we add a negative check. The bash function will exit only if the first echo statement fails or else we will get both the echo statement

The output from this script would be:

We do something
Good Day
The exit status of function is: 0

 

Conclusion

To define a bash function is something is very much important to streamline the script content. Without functions your code may become very messy.
Secondly you should also make an habit to put a description field above every function which explains about the function you have written. Also if the function accepts any input argument then those should be mentioned so that if any third person reads your script then he/she will understand the role of individual function

Lastly I hope the steps from the article to define function in bash on Linux and Unix was helpful. So, let me know your suggestions and feedback using the comment section.

Leave a Comment

Please use shortcodes <cmd>your code</cmd> for syntax highlighting when adding code.