To understand how it works, let's look at the NUM1
variable as an example (the same concept applies to the five variables). We will tell it to read the first parameter {1
from the terminal window, and if it's not supplied by the user, then set it to zero, as in :‐0}
.
Using the default variables, we're not limited to adding five numbers; from now on, we can add as many numbers as we want, but the maximum is five (in the following example, we will add three digits):
root@kali:~# simpleadd.sh 2 4 4 ######################## The total is = 10 ########################
TIP
If you want to know the number of parameters supplied in the script, then you can use the $#
to get the total. Based on the preceding example, the $#
will be equal to three since we're passing three arguments.
If you add the following line after the printf
line:
printf "%s %d\n" "The total number of params =" $#
you should see the following in the terminal window:
root@kali:~# simpleadd.sh 2 4 4 ######################## The total is = 10 The total number of params = 3 ########################
User Input
Another way to interact with the supplied input from the shell script is to use the read function. Again, the best way to explain this is through examples. We will ask the user to enter their first name and last name after which we will print the full name on the screen:
#!/bin/bash read -p "Please enter your first name:" FIRSTNAME read -p "Please enter your last name:" LASTNAME printf "Your full name is: $FIRSTNAME $LASTNAME\n"
To execute it, we just enter the script name (we don't need to supply any parameters like we did before). Once we enter the script's name, we will be prompted with the messages defined in the previous script:
root@kali:~# nameprint.sh Please enter your first name:Gus Please enter your last name:Khawaja Your full name is: Gus Khawaja
Functions
Functions are a way to organize your Bash script into logical sections instead of having an unorganized structure (programmers call it spaghetti code). Let's take the earlier calculator program and reorganize it (refactor it) to make it look better.
This Bash script (in Figure 2.3) is divided into three sections:
In the first section, we create all the global variables. Global variables are accessible inside any function you create. For example, we are able to use all the NUM variables declared in the example inside the add function.
Next, we build the functions by dividing our applications into logical sections. The print_custom() function will just print any text that we give it. We're using the $1 to access the parameter value passed to this function (which is the string CALCULATOR ).
Finally, we call each function sequentially (each one by its name). Print the header, add the numbers, and, finally, print the results.
Figure 2.3 Script Sections
Conditions and Loops
Now that you know the basics of Bash scripting, we can introduce more advanced techniques. When you develop programs in most programming languages (e.g., PHP, Python, C, C++, C#, etc.), including Bash scripting, you will encounter conditions ( if
statements) and loops, as shown in Figure 2.4.
Figure 2.4 Conditions and Loops
Conditions
An if
statement takes the following pattern:
if [[ comparison ]] then True, do something else False, Do something else fi
If you've been paying attention, you know that the best way to explain this pattern is through examples. Let's develop a program that pings a host using Nmap, and we'll display the state of the machine depending on the condition (the host is up or down):
#!/bin/bash #Ping a host using Nmap ### Global Variables ### #Store IP address IP_ADDRESS=$1 function ping_host(){ ping_cmd=$(nmap -sn $IP_ADDRESS | grep 'Host is up' | cut -d '(' -f 1) } function print_status(){ if [[ -z $ping_cmd ]] then echo 'Host is down' else echo 'Host is up' fi } ping_host print_status
The nmap
command either returns an empty string text if the host is down or returns the value “Host is up” if it's responding. (Try to execute the full nmap
command in your terminal window to visualize the difference. If so, replace $IP_ADDRESS
with a real IP address.) In the if
condition, the ‐z
option will check if the string is empty; if yes, then we print “Host is down” or else we print “Host is up:”
root@kali:~# simpleping.sh 10.0.0.11 Host is down root@kali:~# simpleping.sh 10.0.0.1 Host is up
What about other condition statements? In fact, you can compare numbers, strings, or files, as shown in Tables 2.1, 2.2, and 2.3.
Table 2.1 Numerical Conditions
Equal |
[[ x ‐eq y ]]
|
Not equal |
[[ x ‐ne y ]]
|
Less than |
[[ x ‐lt y ]]
|
Greater than |
[[ x ‐gt y ]]
|
Table 2.2 String Conditions
Equal |
[[ str1 == str2 ]]
|
Not equal |
[[ str1 != str2 ]]
|
Empty string |
[[ ‐z str ]]
|