Functions are modular building blocks for creating powerful and modular scripts, using function makes it easy to isolate a code since it would be in a single building block, which would be isolated from the rest of the script.
To put it simply, functions are a block of code or script within a script, here are some of the uses of functions in bash
- It can help make your script more readable and avoid writing the same code multiple times, this is call re-usability, once a function is coded, it can be applied multiple times in the script. You can also port it to another script.
- Instead of sifting through long spaghettis of code, functions make it easier to figure out what a particular part of code is supposed to do.
- Instead of debugging the whole code in a script, you can debug functions by enclosing into set -x and set +x to nitpick that specific function that you feel is problematic, cool right!
That said, let's go over how to use a function in bash...
Functions exist in memory as named elements, you can either create it within your shell environment or in a script. To display the functions residing in your shell environment, you can use the run the following code:
declare -F
This command would return all the inbuilt functions as well as the ones you've created. To see what codes a certain function has, you can use the type command, e.g:
user@server:~$ type _known_hosts
_known_hosts is a function
_known_hosts ()
{
local cur prev words cword;
_init_completion -n : || return;
local options;
[[ "$1" == -a || "$2" == -a ]] && options=-a;
[[ "$1" == -c || "$2" == -c ]] && options+=" -c";
_known_hosts_real $options -- "$cur"
}
As you can see, it indicated that the _known_hosts is a function, and it also output the code of the _known_hosts function. Now unto creating a function...
The syntax for creating a function is as follows:
function <function-name> { <code to execute> }
Let's create a quick function that resides in our shell environment, we would create one in a script later.
Note: The function you create at the user prompt will be lost when the shell is closed or the function is unset. To allow the function to persist, we need to add this to the login script of our user account.
function user_details {
echo
echo "User list"
who
echo
echo "User Last login"
lastlog
echo
echo "Current User"
whoami
}
The above function is a simple function that shows aggregate user details. To print the detail of the function, use the type command, e.g:
user@server:~$ type user_details
user_details is a function
user_details ()
{
echo;
echo "User list";
who;
echo;
echo "User Last login";
lastlog;
echo;
echo "Current User";
whoami
}
To execute the function, you simple enter user_details, and we will see the output of the commands: who, lastlog, and whoami. This is a pretty basic function, we would expand on this later.
In getting started with the bash guide, we covered customizing script with an argument, where we pass an argument to the script, we can also do the same to function that also accepts parameters that can make our code more dynamic.
Consider the following example:
rename 's/Old/New/' *.txt
rename is a GNU rename utility that is used to change a file name, the above code would rename all the "Old" string in the file name with "New" in all jpg files.
If you are wondering what the 's' those, it means to substitute. The rename utility would search for the first term "Old", and the second term "New" is what it will be substituted with.
To move this into a function, we need to think of a great and readable name. I'll go with rename_filename, we create it as follows:
function rename_filename {
rename 's/old/new/' *"$1"
}
We use positional parameters to accept command-line arguments, what I am doing is replacing the hardcoded file extension (.txt) we used previously with $1 within the function. I quoted the variable to protect against spaces within the file extension.
Let me show you an example of how to use this:
- Create a temporary directory e.g mkdir temp
- cd into the temp directory: cd temp
- create multiple txt files using brace extension for illustration purposes: touch old{01..100}.txt
- If you list the content of the directory, you'll see you have 100 dummy files created
- Now copy and paste the function we just created in your shell
- To make use of the function simply type rename_filename .txt
- Now, if you list the content of the temp directory, you'll see the "old" string has been replaced with "new"
Output:
user@server:~/temp$ rename_filename .txt
user@server:~/temp$ ls
new001.txt new010.txt new019.txt new028.txt new037.txt new046.txt new055.txt new064.txt new073.txt new082.txt new091.txt new100.txt
new002.txt new011.txt new020.txt new029.txt new038.txt new047.txt new056.txt new065.txt new074.txt new083.txt new092.txt
new003.txt new012.txt new021.txt new030.txt new039.txt new048.txt new057.txt new066.txt new075.txt new084.txt new093.txt
new004.txt new013.txt new022.txt new031.txt new040.txt new049.txt new058.txt new067.txt new076.txt new085.txt new094.txt
new005.txt new014.txt new023.txt new032.txt new041.txt new050.txt new059.txt new068.txt new077.txt new086.txt new095.txt
new006.txt new015.txt new024.txt new033.txt new042.txt new051.txt new060.txt new069.txt new078.txt new087.txt new096.txt
new007.txt new016.txt new025.txt new034.txt new043.txt new052.txt new061.txt new070.txt new079.txt new088.txt new097.txt
new008.txt new017.txt new026.txt new035.txt new044.txt new053.txt new062.txt new071.txt new080.txt new089.txt new098.txt
new009.txt new018.txt new027.txt new036.txt new045.txt new054.txt new063.txt new072.txt new081.txt new090.txt new099.txt
This function is still in memory, and as soon as you logout it won't persist, however, we can add it to a login script or even a shell script.
Keep note that if you adding a function in a shell script, the functions should always be created at the start of the script as they need to be stored in memory by the time they are called.
Think of it as a portion of prepared food, your food needs to be prepared before you serve it.
Let's create a script:
#!/bin/bash
# Author: The_Devsrealm_Guy
# Website: https://devsrealm.com
# Script to Rename Multiple File Names
# Last Edited: September 2020
function is_string {
if [[ -z "$1" ]] ; then
echo "You should enter the file extension you want to exectute the operation on"
exit 2
fi
}
function rename_filename {
is_string "$1"
echo "File Successfully Renamed"
rename 's/old/new/' *"$1"
}
read -p "Enter the extension you want to perform the rename operation on :"
rename_filename "$REPLY"
exit 1
We provided two functions withing the script. The first one, is_string checks if user supplied a string, if no, it output "You should enter the file extension..."
Then we declare the rename_filename function that simply renames the file names on the extension that the user-supplied. You can see I called the is_string function within the rename_filename function.
At the bottom of the script, we have a prompt for the extension, and we then run the rename_filename function, which in turn calls the is_string function. The thing is, the function has to be created at the state of the script so they can be stored in memory before called. Remember, you need to prepare a portion of food, before serving ;)
EOF