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 usingparenthesis
withfunction
- 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 replacingfunction_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 ourfunction
print_name
and starting of our function block withOPEN
curly brace{
Line 4
contains the command to be executed inside thefunction
bodyLine 5
contains theCLOSE
curly braces}
- On
Line 8
we will call our function by just writing thefunction
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 definedSOME_VAR
which will be our global variableLine 6
we have re-definedSOME_VAR
inside the function print_name block, since this is limited to thefunction
block, it will be considered as local variableLine 11
we check the value ofSOME_VAR
. At this stage since the function print_name is not executed yet, so the content ofSOME_VAR
would be "GLOBAL
"Line 14
we execute the function which would also execute theSOME_VAR
variable within the function block- In
Line 17
we re-check the content ofSOME_VAR
and now it will be changed toLOCAL
because the functionprint_name
has now made this as global variable - So after
Line 14
, any command or function if tries to useSOME_VAR
then the value of this variable would beLOCAL
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 yourfunction
#!/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
outsidefunction
block - In layman's terms,
return
is used as an alternate forexit
statement. (Although both are not same) - The advantage with
return
is that you can choose to come out of afunction
without actually coming out of the script. - If you have already heard of
continue
,break
as I explained in my earlier articles withfor
andwhile
loop then you may get confuse withreturn
as it may sound familiar continue
andbreak
are used to come out of the loop conditions only but the additional advantage withreturn
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_valueLine 5
we are printing a simple statement on the screen using echoLine 6-10
we are check the exit status of echo command- At
Line 7
if the exit status is 0 thenreturn 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 samefunction
block - NOW the mistake which I have done is that I have also put an
echo
after thereturn
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 thefunction
and again atLine 19
we check the exist status of thefunction
Line 21
we print a statement with the exit code of thefunction
. This exit code should match thereturn
code from within thefunction
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.