Bash Scripts — Part 6 — Functions and Library Development
While developing bash scripts, sooner or later you will come across the fact that you periodically have to use the same code fragments. Typing them by hand is boring all the time, and copying and pasting is not our method. How to be? It would be nice to find a tool that allows you to write a block of code once and, when you need it again, just refer to it in the script. The bash shell provides this capability by allowing you to create functions. Bash functions are named blocks of code that can be reused in scripts.
Function declaration
The function can be declared like this:
functionName {
}Or like this:
functionName() {
}The function can be called with no arguments and with arguments.
Using functions
Let’s write a script that contains a function declaration and uses it:
#!/bin/bash
function myfunc {
echo "This is an example of using a function"
}
count=1
while [ $count -le 3 ]
do
myfunc
count=$(( $count + 1 ))
done
echo "This is the end of the loop"
myfunc
echo "End of the script"A function named myfunc. To call a function, just specify its name.
raevskym@DESKTOP-JNF3L6H:~/bash_course$./myscript.sh
This is an example of using a function
This is an example of using a function
This is an example of using a function
This is the end of the loop
This is an example of using a function
End of the scriptThe function can be called as many times as needed. Please note that if you try to use the function before declaring it, you will encounter an error. Let’s write a script to demonstrate this:
#!/bin/bash
count=1
while [ $count -le 3 ]
do
myfunc
count=$(( $count + 1 ))
done
echo "This is the end of the loop"
function myfunc {
echo "This is an example of using a function"
}
echo "End of the script"As expected, nothing good has happened since its launch.
raevskym@DESKTOP-JNF3L6H:~/bash_course$./myscript.sh
./myscript.sh: line 5: myfunc: command not found
./myscript.sh: line 5: myfunc: command not found
./myscript.sh: line 5: myfunc: command not found
This is the end of the loop
End of the scriptWhen coming up with names for functions, keep in mind that they must be unique, otherwise, problems cannot be avoided. If you override a previously declared function, the new function will be called instead of the old one without any notification or error messages. Let’s demonstrate this with an example:
#!/bin/bash
function myfunc {
echo "The first function definition"
}
myfunc
function myfunc {
echo "The second function definition"
}
myfunc
echo "End of the script"As you can see, the new function has quietly overwritten the old one.
raevskym@DESKTOP-JNF3L6H:~/bash_course$./myscript.sh
The first function definition
The second function definition
End of the scriptUsing the return command
The command returnallows you to specify the integer exit code returned by the function. There are two ways to work with what is the result of a function call. Here's the first one:
#!/bin/bash
function myfunc {
read -p "Enter a value: " value
echo "adding value"
return $(( $value + 10 ))
}
myfunc
echo "The new value is $?"The command echodisplayed the sum of the entered number and the number 10.
raevskym@DESKTOP-JNF3L6H:~/bash_course$./myscript.sh
Enter a value: 10
adding value
The new value is 20The functionmyfuncadds 10 to the number contained in the variable$value, the value of which is set by the user while the script is running. Then it returns the result using the commandreturn. What the function returned is output by the commandechousing a variable$?.
If you execute any other command before extracting the$?function's return value from the variable, that value will be lost. The point is that this variable stores the return code of the last executed command.
Note that the maximum number that the command can returnreturnis 255. If the function needs to return a larger number or string, a different approach is needed.
Writing the output of a function to a variable
Another way to return the results of a function’s work is to write the data output by the function to a variable. This approach allows you to bypass the limitations of the command returnand return any data from the function. Let's consider an example:
#!/bin/bash
function myfunc {
read -p "Enter a value: " value
echo $(( $value + 10 ))
}
result=$( myfunc)
echo "The value is $result"This is what you get after calling this script.
raevskym@DESKTOP-JNF3L6H:~/bash_course$./myscript.sh
Enter a value: 10
The value is 20Function arguments
Think of bash functions as small snippets of code that save you time and space by eliminating the need to constantly type or copy the same sets of commands. However, the capabilities of the functions are much wider. In particular, we are talking about passing arguments to them.
Functions can use standard positional parameters that store what is passed to them when called. For example, the name of a function is stored in a parameter $0, the first argument passed to it is in $1, the second in $2, and so on. The number of arguments passed to the function can be found by accessing the variable $#. If you are familiar with the third part, you can't help but notice that this is all very similar to how scripts handle command line parameters passed to them.
Arguments are passed to the function by writing them after its name:
myfunc $val1 10 20Here’s an example in which a function is called with arguments and handles their processing:
#!/bin/bash
function addnum {
if [ $# -eq 0 ] || [ $# -gt 2 ]
then
echo -1
elif [ $# -eq 1 ]
then
echo $(( $1 + $1 ))
else
echo $(( $1 + $2 ))
fi
}
echo -n "Adding 10 and 15: "
value=$(addnum 10 15)
echo $value
echo -n "Adding one number: "
value=$(addnum 10)
echo $value
echo -n "Adding no numbers: "
value=$(addnum)
echo $value
echo -n "Adding three numbers: "
value=$(addnum 10 15 20)
echo $valueLet’s run the script.
raevskym@DESKTOP-JNF3L6H:~/bash_course$./myscript.sh
Adding 10 and 15: 25
Adding one number: 20
Adding no numbers: -1
Adding three numbers: -1The functionaddnumchecks the number of arguments passed to it when called from a script. If there are none, or there are more than two, the function returns -1. If there is only one parameter, it adds it to itself and returns the result. If there are two parameters, the function adds them.
Please note that the function cannot directly work with parameters that are passed to the script when it is run from the command line. For example, let's write a script like this:
#!/bin/bash
function myfunc {
echo $(( $1 + $2 ))
}
if [ $# -eq 2 ]
then
value=$( myfunc)
echo "The result is $value"
else
echo "Usage: myfunc a b"
fiWhen it is launched, or rather, when the function declared in it is called, an error message will be displayed.
raevskym@DESKTOP-JNF3L6H:~/bash_course$./myscript.sh 10 20
./myscript.sh: line 3: + : syntax error: operand expected (error token is "+ ")
The result isInstead, if the function is going to use the parameters passed to the script when called from the command line, you must pass them to it when called:
#!/bin/bash
function myfunc {
echo $(( $1 + $2 ))
}
if [ $# -eq 2 ]
then
value=$(myfunc $1 $2)
echo "The result is $value"
else
echo "Usage: myfunc a b"
fiEverything is working correctly now:
raevskym@DESKTOP-JNF3L6H:~/bash_course$./myscript.sh
Usage: myfunc a b
raevskym@DESKTOP-JNF3L6H:~/bash_course$./myscript.sh 10 20
The result is 30Working with variables in functions
The variables we use in scripts are scoped. These are the places in the code from which you can work with these variables. Variables declared inside functions behave differently from the variables we have already encountered. They can be hidden from other parts of the scripts.
There are two kinds of variables:
- Global variables.
- Local variables.
Global variables
Global variables are variables that are visible from anywhere in the bash script. If you have declared a global variable in the main script code, you can refer to such a variable from a function.
Much the same is true for global variables declared in functions. You can also refer to them in the main script code after calling the functions.
By default, all variables declared in scripts are global. So, variables declared outside of functions can be accessed from functions without problems:
#!/bin/bash
function myfunc {
value=$(( $value + 10 ))
}
read -p "Enter a value: " value
myfunc
echo "The new value is: $value"This is what this script will output:
raevskym@DESKTOP-JNF3L6H:~/bash_course$./myscript.sh
Enter a value: 10
The new value is: 20When a variable is assigned a new value in a function, that new value is not lost when the script calls it after the function finishes. This is what can be seen in the previous example.
What if this behavior doesn’t suit us? The answer is simple — you need to use local variables.
Local variables
Variables that are declared and used inside a function can be declared local. To do this, use the keyword localbefore the variable name:
local temp=$(( $value + 5 ))If there is a variable with the same name outside the function, it will not be affected. The keyword localallows you to separate the variables used inside the function from other variables. Let's consider an example:
#!/bin/bash
function myfunc {
local temp=$[ $value + 5 ]
echo "The Temp from inside function is $temp"
}
temp=4
myfunc
echo "The temp from outside is $temp"Let’s run the script:
raevskym@DESKTOP-JNF3L6H:~/bash_course$./myscript.sh
The Temp from inside function is 5
The temp from outside is 4Here, when we work with a variable$tempinside a function, it does not affect the value assigned to a variable with the same name outside of it.
Passing Arrays to Functions as Arguments
Let’s try to pass an array as an argument to the function. I would like to say right away that such a construction will not work correctly:
#!/bin/bash
function myfunc {
echo "The parameters are: $@"
arr=$1
echo "The received array is ${arr[*]}"
}
myarray=(1 2 3 4 5)
echo "The original array is: ${myarray[*]}"
myfunc $myarrayAs you can see from the example, when you pass an array function, it will only access its first element:
raevskym@DESKTOP-JNF3L6H:~/bash_course$./myscript.sh
The original array is: 1 2 3 4 5
The parameters are: 1
The received array is 1In order to solve this problem, it is necessary to extract the data contained in it from the array and pass them to the function as independent arguments. If necessary, inside the function, the arguments received by it can be reassembled into an array:
#!/bin/bash
function myfunc {
local newarray
newarray=("$@")
echo "The new array value is: ${newarray[*]}"
}
myarray=(1 2 3 4 5)
echo "The original array is ${myarray[*]}"
myfunc ${myarray[*]}Let’s run the script:
raevskym@DESKTOP-JNF3L6H:~/bash_course$./myscript.sh
The original array is 1 2 3 4 5
The new array value is: 1 2 3 4 5As you can see from the example, the function assembled an array from the arguments passed to it.
Recursive functions
Recursion is when a function calls itself. A classic example of recursion is a function to calculate a factorial. The factorial of a number is the product of all natural numbers from 1 to that number. For example, factorial 5 can be found like this:
5! = 1 * 2 * 3 * 4 * 5If you write the formula for calculating the factorial in a recursive form, you get the following:
x! = x * (x-1)!You can use this formula to write a recursive function:
#!/bin/bash
function factorial {
if [ $1 -eq 1 ]
then
echo 1
else
local temp=$(( $1 - 1 ))
local result=$(factorial $temp)
echo $(( $result * $1 ))
fi
}
read -p "Enter value: " value
result=$(factorial $value)
echo "The factorial of $value is: $result"Let’s check if this script works correctly:
raevskym@DESKTOP-JNF3L6H:~/bash_course$./myscript.sh
Enter value: 5
The factorial of 5 is: 120As you can see, everything works as it should.
Creating and using libraries
So now you know how to write functions and how to call them in the same script where they are declared. What if you need to use a function, the block of code that it is, in another script, without using copy and paste?
The bash shell allows you to create so-called libraries — files containing functions, and then use these libraries in any scripts where they are needed.
The key to using libraries is in command source. This command is used to link libraries to scripts. As a result, the functions declared in the library become available in the script, otherwise, the functions from the libraries will not be available in the scope of other scripts.
Teamsourcethere is an alias - the operator "dot". In order to include a file in a script, you need to add a structure of the following type to the script:
. ./myscriptSuppose we have a file myfuncsthat contains the following:
function addnum {
echo $(( $1 + $2 ))
}This is a library. Let’s use it in the script:
#!/bin/bash
. ./myfuncs
result=$(addnum 10 20)
echo "The result is: $result"Let’s call it:
raevskym@DESKTOP-JNF3L6H:~/bash_course$./myscript.sh
The result is: 30We have just used a library function inside a script. All this is great, but what if we want to call a function declared in the library from the command line?
Calling bash functions from the command line
If you have mastered the previous part of this series, you probably already guess that a function from a library can be included in a file. bashrcusing the command source. As a result, the function can be called directly from the command line.
Edit .bashrcto add a line like this (the path to the library file on your system will naturally be different):
. /home/raevskym/Desktop/myfuncsNow the function can be called directly from the command line:
raevskym@DESKTOP-JNF3L6H:~/bash_course$ addnum 10 20
30It is even more pleasant considering that such a library is available to all child processes of the shell, that is, it can be used in bash scripts without worrying about connecting this library to them.
It is worth noting here that in order for the above example to work, you may need to log out and then log back in. Also, note that if the name of a function from the library matches the name of a standard command, the function will be called instead. Therefore, be careful about function names.
Outcome
Functions in bash scripts allow you to style blocks of code and call them in scripts. And the most frequently used functions should be separated into libraries that can be connected to scripts using the operator source. If among your functions there are some that you just can't live without, libraries with them can be connected in a file .bashrc. This will allow you to conveniently use them on the command line or in other scripts. The main thing is that the names of your functions do not match the names of the built-in commands.
That's all for today. Next time, let's talk about a sed that is a powerful string processing utility.
Dear Readers! Do you use in-house developed functions to solve everyday problems?






