Introduction
Functions in Bash Scripting are a great way to reuse code. In this section of our Bash scripting tutorial you’ll learn how they work and what you can do with them.
Think of a function as a small script within a script. It’s a small piece of code that you can call multiple times within your script. They are particularly useful if you have certain tasks that need to be done multiple times. Instead of writing the same code over and over again, you can write it once in a function and then call that function each time.
Functions
Creating a function is pretty easy. They can be written in two different formats
: function_name () {<commands> }
or
function
function_name {<commands> } Some
points to note:
- Any of the above methods for specifying a function is valid. Both operate the same and there is no advantage or disadvantage for one over the other. It’s really just personal preference.
- In other programming languages it is common to have arguments passed to the function listed inside the square brackets (). In Bash they are there only to decorate and you never put anything inside them.
- The definition of the function (the actual function itself) must appear in the script before any call to the function.
Let’s look at a simple example
:
Let’s break it down:
Line
- 4 – We start defining the function by giving it a name
- Line 5 – Within the brackets we can have as many commands as we
- Lines 8 and 9 – Once the function is defined, we can call it as many times as we want and it will execute those commands.
.
want.
It
is often the case that we would like the function to process some data for us. We can send data to the function in a similar way to passing command-line arguments to a script. We provide the arguments directly after the function name. Within the function are accessible as $1, $2, etc.
Most
other programming languages have the concept of a return value for functions, a means for the function to send data to the original call location. Bash functions do not allow us to do this. However, they allow us to establish a return state. Similar to how a program or command comes out with an output status that indicates whether it was successful or not. We use the return keyword to indicate a return status.
Let’s break it down Line
- 6 – The return status does not have to be encoded. It can be a
- Line 11 – Remember that the variable $? contains the return state of the command or function executed earlier.
variable
If all you want to do is return a number (for example, the result of a calculation), you might consider using the return state to achieve this. It’s not the intended purpose, but it will work.
One way to avoid this is to use command substitution and have the function print the result (and only the result).
Let’s break it down:
Line 5 – This command will print the number of lines in the
- referred file for $1
- Line 8 – We use command substitution to take what would normally be printed on the screen and assign it to the variable num_lines
.
Just be careful if you take this approach, because if you don’t call the function with command substitution, it will print the result on the screen. Sometimes that’s okay because that’s what you want. Other times that may be undesirable.
Variable
scope
The scope refers to which parts of a script can see which variables. By default, a variable is global. This means that it is visible everywhere in the script. We can also create a variable as a local variable. When we create a local variable within a function, it is only visible within that function. To do that, we use the local keyword in front of the variable the first time we set its value.
local
var_name=<var_value>
In general, it is considered good practice to use local variables within functions to keep everything within the contained function. In this way, variables are safer from being inadvertently modified by another part of the script that has a variable with the same name (or vice versa).
The scope can sometimes be difficult to understand at first. If it seems a bit confusing, the best approach is to create a Bash script similar to the one above and modify it several times by setting and changing variables in different places and then observing the behavior when you run it.
Override
commands You can name a function with the same name as a command you would normally use on the command line. This allows us to create a wrapper. Eg. Maybe every time we call the ls command in our script, what we really want is ls -lh. We could do the following
:
Let’s break it down:
- Line 5 – When we have a function with the same name as a command, we need to put the command keyword in front of the name when we want the command instead of the function, since the function normally takes precedence.
In the example above, if we did not put the command of keyword in front of ls on line 5, we would end up in an endless loop. Although we are inside the ls function when we call ls we would have called another instance of the ls function which in turn would have done the same thing and so on.
Design
Creating functions in your Bash scripts is easy. However, creating good features that make your scripts easier to write and maintain takes time and expertise. As with most things with computers, when you reach this level of complexity, there will be several ways you could achieve the desired result. Some will be better than others, so take the time to think about different ways you could write your code and how it can be better.
Sometimes better is
fewer lines of code, sometimes better is easier to modify later if requirements change. Sometimes better is the approach that is less prone to errors.
If a particular task needs to be performed multiple times, then it is a good candidate to place it within a function.
Sometimes it is good to put auxiliary tasks within the functions as well so that they are logically separated from the main part of the script. A common example is validating input (for example, making sure a specified file exists and is readable).
A function is most reusable when it performs a single task and a single task. Instead of having one large function, consider dividing it into several functions and dividing the task.
However, you need to find the right balance. If the functions are too large and take too much processing, then you don’t get the full benefit. If it is divided into too many functions, your code can easily grow and become dumb. With experience you will find that sweet spot in the middle.
Summary
of activities
There is no activity for this section. What I suggest you do is go back to the activities in the previous section and redo them using functions.