📜 ⬆️ ⬇️

Bash scripts, part 6: functions and library development

Bash scripts: start
Bash scripts, part 2: loops
Bash scripts, part 3: command line options and keys
Bash scripts, part 4: input and output
Bash Scripts, Part 5: Signals, Background Tasks, Script Management
Bash scripts, part 6: functions and library development
Bash scripts, part 7: sed and word processing
Bash scripts, part 8: awk data processing language
Bash scripts, part 9: regular expressions
Bash scripts, part 10: practical examples
Bash scripts, part 11: expect and automate interactive utilities

Being engaged in the development of bash-scripts, you will sooner or later encounter the fact that you periodically have to use the same code fragments. Constantly typing them manually is boring, 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, allowing you to create functions. Bash functions are named blocks of code that can be reused in scripts.


')

Function declaration


You can declare a function like this:

functionName { } 

Or so:

 functionName() { } 

The function can be called without arguments and with arguments.

Use of functions


Let's write a script containing the function declaration and using 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" 

Here is a function called myfunc . To call a function, it is enough to specify its name.


Function call results

The function can be called as many times as necessary. Please note that trying to use the function before its declaration, you will encounter an error. Let us write a script demonstrating 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 happened after its launch.


Attempt to use the function before its announcement

When 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 notifications or error messages. Let us 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 quietly wiped out the old one.


Function override

Using the return command


The return command allows you to specify the integer completion code returned by the function. There are two ways to deal with what is the result of a function call. Here is the first:

 #!/bin/bash function myfunc { read -p "Enter a value: " value echo "adding value" return $(( $value + 10 )) } myfunc echo "The new value is $?" 

The echo team found the sum of the entered number and the number 10.


Output of the value returned by the function

The myfunc adds 10 to the number that is contained in the $value variable, the value of which is set by the user while the script is running. It then returns the result using the return command. What the function returned is displayed with the echo command using the $? variable $? .
If you execute any other command before extracting from the $? variable $? the value returned by the function, this value will be lost. The fact is that this variable stores the return code of the last command executed.

Note that the maximum number that the return command can return is 255. If the function should return a larger number or string, another approach will be needed.

Writing function output to a variable


Another way to return the results of a function is to write the data output by the function to a variable. This approach allows you to bypass the limitations of the return command and return any data from the function. Consider an example:

 #!/bin/bash function myfunc { read -p "Enter a value: " value echo $(( $value + 10 )) } result=$( myfunc) echo "The value is $result" 

That's what happens after calling this script.


Writing the results of the function to a variable

Function arguments


The bash functions can be thought of as small pieces of code that save time and space, eliminating the need to constantly type from the keyboard or copy the same command sets. However, the possibilities of functions are much wider. In particular, we are talking about the transfer of arguments to them.

Functions can use standard positional parameters, which write what is passed to them when they are called. For example, the function name is stored in the $0 parameter, the first argument passed to it is in $1 , the second is 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 of this cycle of materials, you can not help but notice that all this is very similar to how scripts process the command line parameters passed to them.

Arguments pass functions by writing them after her name:

 myfunc $val1 10 20 

Here is an example in which a function is called with arguments and processes them:

 #!/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 $value 

Run the script.


Function call with arguments

The addnum function checks the number of arguments passed to it when calling from the script. If there are none, or more than two, the function returns the value -1. If the parameter is only one, 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 launched from the command line. For example, write the following script:

 #!/bin/bash function myfunc { echo $(( $1 + $2 )) } if [ $# -eq 2 ] then value=$( myfunc) echo "The result is $value" else echo "Usage: myfunc  a b" fi 

When it is launched, or rather, when calling the function declared in it, an error message will be displayed.


The function cannot directly use the parameters passed to the script.

Instead, if the function intends to use the parameters passed to the script when called from the command line, you need to pass them to it when you call:

 #!/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" fi 

Now everything works correctly.


The transfer function of the parameters with which the script is running

Work with variables in functions


Variables that we use in scripts are characterized by scope. These are the code points from which you can work with these variables. Variables declared inside functions behave differently from those variables that we have already encountered. They can be hidden from other parts of the scripts.

There are two kinds of variables:


â–ŤGlobal variables


Global variables are variables that are visible from anywhere in the bash script. If you declare a global variable in the main script code, such a variable can be accessed from a function.

Almost the same is true for global variables declared in functions. You can also access 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 easily be accessed from functions:

 #!/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.


Accessing a global variable from a function

When a variable is assigned a new value in a function, this new value is not lost when the script accesses it after the function ends. This is what can be seen in the previous example.

What if this behavior does not 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 local keyword in front of the variable name:

 local temp=$(( $value + 5 )) 

If there is a variable with the same name outside the function, it will not affect it. The local keyword allows you to separate variables used inside a function from other variables. 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" 

Run the script.


Local variable in function

Here, when we work with the $temp variable inside a function, this 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 functions to the array as an argument. I just want to say that this construction will work incorrectly:

 #!/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 $myarray 


Wrong Approach to Passing Array Functions

As can be seen from the example, when transferring the function of an array, it will get access only to its first element.

In order to solve this problem, it is necessary to extract the data available in it from the array and transfer their functions as independent arguments. If necessary, inside the function, the arguments it receives 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[*]} 

Run the script.


Build an array inside a function

As you can see from the example, the function collected an array of the arguments passed to it.

Recursive functions


Recursion is when a function calls itself. The classic example of recursion is the function for calculating 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 as follows:

 5! = 1 * 2 * 3 * 4 * 5 

If you write the formula for calculating factorial in recursive form, you get the following:

 x! = x * (x-1)! 

This formula can be used 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" 

Check if this script works correctly.


Factorial calculation

As 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, that block of code that it represents, in another script, without using copy and paste?

The bash shell allows you to create so-called libraries - files that contain functions, and then use these libraries in any scripts where they are needed.

The key to using libraries is in the source command. This command is used to connect 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.

The source command has an alias — the dot operator. In order to connect the file in the script, add the following construction to the script:

 . ./myscript 

Suppose we have a file myfuncs that 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" 

Call it.


Use of libraries

We have just used the library function inside the 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 the function from the library can be included in the file. bashrc using the source command. As a result, the function can be called directly from the command line.

Edit .bashrc , adding the following line to it (the path to the library file on your system, of course, will be different):

 . /home/likegeeks/Desktop/myfuncs 

Now the function can be called directly from the command line:

 $ addnum 10 20 


Calling a function from the command line

Even more pleasant is that such a library is available to all child shell processes, that is, it can be used in bash scripts without worrying about connecting this library to them.

It is worth noting that in order for the above example to work, you may need to log out and then log in again. In addition, note that if the name of the function from the library matches the name of a standard command, the function will be called instead. Therefore, pay attention to the function names.

Results


Functions in bash scripts allow you to decorate blocks of code and call them in scripts. And the most frequently used functions should be allocated to libraries that can be connected to scripts using the source operator. If among your functions there are those without which you just can’t live without - libraries with them can be included in the .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 coincide with the names of the built-in commands.

That's all for today. Next time, let's talk about the sed — utility sed — powerful string handling tool.



Dear readers! Do you use the functions of your own design to solve everyday problems?

Source: https://habr.com/ru/post/327248/


All Articles