© Ashwin Pajankar 2021
A. PajankarPractical Linux with Raspberry Pi OShttps://doi.org/10.1007/978-1-4842-6510-9_6

6. Shell Scripting

Ashwin Pajankar1  
(1)
Nashik, Maharashtra, India
 

In the last chapter, we learned a few more useful commands in Unix and the RPi OS. These commands and tools we learned are extremely useful in writing shell scripts.

Continuing the theme of Unix and RPi OS commands of the last chapter, we will get started with shell scripting in this chapter and continue it to the next chapter. The following is the list of topics we will learn in this chapter:
  • Unix File Permissions

  • Command: nohup

  • Beginning Shell Scripting

  • User Input

  • Expressions in the Shell

  • If Statement

  • Switch Case

  • Length of a Shell Variable

  • Command-Line Arguments

  • Function

  • Loops in the Shell

  • Comparing Strings

  • File Operations

After this chapter, we will be comfortable writing shell scripts on all Unix-like operating systems.

Unix File Permissions

Let us understand this concept by example. Run the following command in the lxterminal:
ls -l
The output is as follows:
pi@raspberrypi:~ $ ls -l
total 76
drwxr-xr-x 2 pi pi 4096 Aug 20 16:10 Bookshelf
drwxr-xr-x 2 pi pi 4096 Aug 20 16:40 Desktop
drwxr-xr-x 2 pi pi 4096 Aug 20 16:40 Documents
drwxr-xr-x 2 pi pi 4096 Aug 20 16:40 Downloads
drwxr-xr-x 3 pi pi 4096 Aug 28 08:40 gnomeforpi
drwxr-xr-x 2 pi pi 4096 Aug 20 16:40 Music
drwxr-xr-x 2 pi pi 4096 Aug 20 16:40 Pictures
-rwxr-xr-x 1 pi pi 7980 Aug 29 17:36 prog00
-rw-r--r-- 1 pi pi   76 Aug 29 17:36 prog00.c
-rw-r--r-- 1 pi pi   22 Aug 29 18:38 prog00.py
-rwxr-xr-x 1 pi pi 8740 Aug 29 17:49 prog01
-rw-r--r-- 1 pi pi   93 Aug 29 17:48 prog01.cpp
drwxr-xr-x 2 pi pi 4096 Aug 20 16:40 Public
drwxr-xr-x 2 pi pi 4096 Aug 20 16:40 Templates
-rw-r--r-- 1 pi pi    3 Sep  3 16:06 test1.sh
drwxr-xr-x 2 pi pi 4096 Aug 20 16:40 Videos
This is the Unix long list format. We have already seen this. Let us understand the meaning of all the terms in the output. Let us see the following two lines:
drwxr-xr-x 2 pi pi 4096 Aug 20 16:40 Pictures
-rwxr-xr-x 1 pi pi 7980 Aug 29 17:36 prog00

As we can see, there are nine columns in the output. The first column (drwxr-xr-x and -rwxr-xr-x) tells us about the file type and permissions. The first character is d if it is a directory and if it is a file. The rest of the nine characters tell us about the permissions. We will see them in detail soon.

The second column has a number. It shows the number of links. The third and fourth columns are the owner and group names (pi and pi in this case). The fifth column shows the size in bytes. For directories, it is always 4 k. If you are interested, you can read more about it at https://askubuntu.com/questions/186813/why-does-every-directory-have-a-size-4096-bytes-4-k.

The next three columns are the last modification time. The last column shows us the name of the directory or file.

Let us discuss permissions in detail. You must have noticed the first column has a string like drwxr-xr-x . As we discussed, the first character denotes the file type. The next nine characters can be divided into three groups of three characters each. They are permissions to the user who created the file/directory, user’s group, and others, respectively.
  • r means read permission.

  • w means write permission.

  • x means execute permission.

If we encounter the symbol anywhere, it means that permission is not granted. So the string -rwxr-xr-x means that it is a file. The creator/owner of the file has all (read, write, and execute) permissions. The owner’s own group has read and execute permissions. And others have read and execute permissions. We can manually alter permissions. We usually use numerical representation of the strings for the permissions:
  • r means 4.

  • w means 2.

  • x means 1.

So, when we need to set permissions for a file/directory, we compute the sum for the owner, group, and others, respectively. For example, if I want to enable all permissions for all, then it will be rwxrwxrwx . The numerical representation will be (4+2+1 4+2+1 4+2+1) which can be written as 777. For reasons of security, we rarely use this. The most common permission is rwxr--r--. It can be represented as (4+2+1 4+0+0 4+0+0) and written as 744. Another common permission format is rwxr-xr-x. It can be represented as (4+2+1 4+0+1 4+0+1) and written as 755. We will soon see how to grant these permissions on files and directories. We needed to understand this concept as it is very important to know it for executing programs on Unix-like operating systems.

Command: nohup

nohup means No Hangup. We use this command on the command prompt in cases where we do not want the program invoked to be terminated if we close the command prompt. We usually use it along with the & operator. To demonstrate this, we need to use the desktop of the RPi OS (either directly or remotely through VNC). Open the lxterminal. And then run the following command:
nohup idle &

It will open the IDLE (Integrated Development and Learning Environment) editor (it is an IDE for Python 3; we will see that in the later part of the book). Now if we close the lxterminal window, it will not close the IDLE editor. However, if we invoke the IDLE with the command idle and nothing else, the IDLE will be closed if we close the lxterminal window used to invoke it.

Beginning Shell Scripting

Run the following command in the lxterminal:
pi@raspberrypi:~ $ echo "Hello World!"
Hello World!
As we can see, it immediately prints the output. We can create a script that has a collection of these statements. The statements in the script are fed to the shell interpreter and executed one by one. Such a script is known as shell script. Let us create one. Open any text editor and paste the command we executed there and save the file with the name prog00.sh. Generally, we use .sh as an extension for the shell script files. It is not necessary to have an extension. It just helps us to identify that these are shell scripts. We can easily list all the shell scripts in a directory with the following command:
ls *.sh
Once you create the file for the shell script, we can run it as follows:
bash prog00.sh
or
sh prog00.sh
Add the command date after the first line and run it again:
pi@raspberrypi:~ $ sh prog00.sh
Hello World!
Fri Sep  4 10:37:50 IST 2020

This is how we can write and execute simple shell scripts.

There is another way we can run the shell scripts. We need to change the permissions of the shell script with the following command:
chmod 755 prog00.sh
We have already discussed the meaning of the permissions represented by 755. Now we can directly run the script using ./ as follows:
./prog00.sh
It will execute the program and print the output. We can explicitly specify the interpreter with something known as shebang or sha-bang . Just add #!/bin/bash as the first line of the script shown in Listing 6-1.
#!/bin/bash
echo "Hello World!"
date
Listing 6-1

prog00.sh

This way the script uses the Bash shell to run when invoked directly.

User Input

We can accept input from a user in our shell script. In Listing 6-2, we are using the statement read to read the user input. We are reading the input into a variable and displaying its value. This is how we can read user input.
#!/bin/bash
echo 'Who am I talking to?'
read name
echo 'Nice to meet you' $name
Listing 6-2

prog01.sh

Expressions in the Shell

Just like any programming language, we can write expressions in the shell. The following shell script (Listing 6-3) shows various ways to write mathematical expressions in the shell.
#!/bin/bash
let a=5+4
echo $a
let "a=5+4"
echo $a
let a++
echo $a
let "a=4*5"
echo $a
Listing 6-3

prog02.sh

In this script, the first, second, and fourth expressions show us an assignment operation, and the third expression shows us an increment operation. We will frequently use expressions to assign values to variables in the shell. We can also use the expr statement to evaluate the arithmetic operations as shown in Listing 6-4.
#!/bin/bash
expr 3 + 4
expr "3 + 4"
expr 11 % 2
a=$( expr 10 - 3 )
echo $a
Listing 6-4

prog03.sh

The first and the third expr statements are arithmetic, and the second one is a string as the operand is enclosed by double quotes. The fourth statement is an assignment statement. Run the script and see the output.

Finally, Listing 6-5 shows a way to write expressions without let or expr.
#!/bin/bash
a=$(( 4 + 5 ))
echo $a
a=$((3+5))
echo $a
b=$(( a + 3 ))
echo $b
b=$(( $a + 4 ))
echo $b
(( b++ ))
echo $b
(( b += 3 ))
echo $b
a=$(( 4 * 5 ))
echo $a
Listing 6-5

prog04.sh

Run the script to see the output.

If Statement

We can have conditional statements using if. They use comparison operators. The following are the comparison operators in Bash:
  • -eq is equal to.

  • -ne is not equal to.

  • -lt is less than.

  • -le is less than or equal to.

  • -gt is greater than.

  • -ge is greater than or equal to.

Listing 6-6 shows usage of the -eq operator with an if statement .
#!/bin/bash
echo 'Please enter an integer: '
read a
if [ $a -gt 100 ]
then
echo "The number is greater than 100."
fi
Listing 6-6

prog05.sh

Run the script and see the output.

We can even have a nested if (Listing 6-7).
#!/bin/bash
echo 'Please enter an integer:'
read a
if [ $a -gt 100 ]
then
echo 'It is greater than 100.'
if (( $a % 2 == 0 ))
then
echo 'It is an even number.'
fi
fi
Listing 6-7

prog06.sh

Run the script and see the output.

We can write an if-else block (Listing 6-8).
#!/bin.bash
echo 'Please enter an integer:'
read a
if [ $a -gt 50 ]
then
echo 'The number is greater than 50.'
else
echo 'The number is less than or equal to 50.'
fi
Listing 6-8

prog07.sh

Run it to see the output. We can even write the if-elif-else statement (Listing 6-9).
#!/bin/bash
echo 'Please enter an integer:'
read a
if [ $a -gt 100 ]
then
echo 'The number is greater than 100.'
elif [ $a -eq 100 ]
then
echo 'The number is equal to 100.'
else
echo 'The number is less than 100.'
fi
Listing 6-9

prog08.sh

Switch Case

We can have a switch case construct (like C, C++, and Java) in the shell. Listing 6-10 is a sample of such construct.
#!/bin/bash
echo 'Please input an integer:'
read a
case $a in
10)
echo Ten
;;
20)
echo Twenty
;;
100)
echo Hundred
;;
*)
echo 'Default Case'
esac
Listing 6-10

prog09.sh

Run the shell script to see the output.

Length of a Shell Variable

We can use the # symbol to compute the length of a variable (Listing 6-11).
#!/bin/bash
a='Hello World!'
echo ${#a}
b=12345
echo ${#b}
Listing 6-11

prog10.sh

Execute the script to know the length of variables.

Command-Line Arguments

Command Line Arguments are the arguments passed to any program (in this context, a shell script) at the time of invoking that script from the command line or any other script. Most of the modern programming (C, C++, and Java) and scripting (shell, Perl, Python) languages have provision for handling command-line arguments.

In a shell script, we can use $# and $@ to handle the command-line arguments as shown in Listing 6-12.
#!/bin/bash
echo 'Total number of arguments:' $#
echo 'All argument values:' $@
echo 'Name of the script:' $0
echo 'First Argument ->' $1
echo 'Second Argument ->' $2
Listing 6-12

prog11.sh

Run it as follows:
pi@raspberrypi:~ $ bash prog11.sh 1 "Hello World" 3.14 ASH
Total number of arguments: 4
All argument values: 1 Hello World 3.14 ASH
Name of the script: prog11.sh
First Argument -> 1
Second Argument -> Hello World

Function

We can even write functions in shell scripts. Functions are reusable blocks of code that are called frequently in a program. If you have a block of code that needs to be used frequently, it makes sense to write a function around it. Listing 6-13 shows a demonstration of a simple function.
#!/bin/bash
print_message ()
{
        echo 'Hello from function'
}
print_message
Listing 6-13

prog12.sh

In the script, print_message() is a function, and we are calling it exactly one time as shown. We are first defining its body and then calling it (when we call, the brackets are not used). We can even have arguments in functions, and they work exactly the same as command-line arguments. You can read more about it at https://bash.cyberciti.biz/guide/Pass_arguments_into_a_function.

Loops in the Shell

We can write a loop using the until statement and comparison operator as shown in Listing 6-14.
#!/bin/bash
counter=0
until [ $counter -gt 5 ]
do
      echo 'Counter:' $counter
      ((counter++))
done
Listing 6-14

prog13.sh

Run the script and it shows the following output:
pi@raspberrypi:~ $ bash prog13.sh
Counter: 0
Counter: 1
Counter: 2
Counter: 3
Counter: 4
Counter: 5
We can even have for loops as shown in Listing 6-15.
#!/bin/bash
for i in 1 2 3 4 5
do
      echo 'Looping ... number' $i
done
Listing 6-15

prog14.sh

The output is as follows:
pi@raspberrypi:~ $ bash prog14.sh
Looping ... number 1
Looping ... number 2
Looping ... number 3
Looping ... number 4
Looping ... number 5
We can compute a factorial with a for loop as shown in Listing 6-16.
#!/bin/bash
echo 'Enter a number'
read num
fact=1
for((i=2;i<=num;i++))
{
      fact=$((fact * i))
}
echo $fact
Listing 6-16

prog15.sh

We can write the same program with a while loop as shown in Listing 6-17.
#!/bin/bash
echo 'Enter a number:'
read num
fact=1
while [ $num -gt 1 ]
do
      fact=$((fact * num))
      num=$((num - 1))
done
echo $fact
Listing 6-17

prog16.sh

Run all these programs to see the loops in action.

Comparing Strings

We can compare strings in the shell with string comparison operators. Listing 6-18 shows string comparison in action.
#!/bin/bash
a='GNU'
b='Linux'
if [ $a = $b ]
then
        echo "$a = $b : a is equal to b"
else
        echo "$a = $b : a is not equal to b"
fi
if [ $a != $b ]
then
        echo "$a = $b : a is not equal to b"
else
        echo "$a = $b : a is equal to b"
fi
if [ -z $a ]
then
        echo "-z $a : length of a is zero"
else
        echo "-z $a : length of a is not zero"
fi
if [ -n $a ]
then
        echo "-n $a : length of a is not zero"
else
        echo "-n $a : length of a is zero"
fi
if [ $a ]
then
        echo "$a : string is not empty"
else
        echo "$a : string is empty"
fi
Listing 6-18

prog17.sh

We can change the values of strings stored in variables a and b to experiment with different outcomes.

File Operations

We can check files for various conditions with the following operators:
  • -r checks if the file is readable.

  • -w checks if the file is writeable.

  • -x checks if the file is executable.

  • -f checks if the file is an ordinary file.

  • -d checks if the file is a directory.

  • -s checks if the file size is zero.

  • -e checks if the file exists.

Listing 6-19 shows the usage of all these operators.
#!/bin/bash
file='prog12.sh'
if [ -r $file ]
then
        echo 'File has read access.'
else
        echo 'File does read access.'
fi
if [ -w $file ]
then
        echo 'File has write permission.'
else
        echo 'File does not have write permission.'
fi
if [ -x $file ]
then
        echo 'File has execute permission.'
else
        echo 'File does not have execute permission.'
fi
if [ -f $file ]
then
        echo 'File is an ordinary file.'
else
        echo 'File is not an ordinary file.'
fi
if [ -d $file ]
then
        echo 'File is a directory.'
else
        echo 'File is not a directory.'
fi
if [ -s $file ]
then
        echo 'File size is not zero.'
else
        echo 'File size is zero.'
fi
if [ -e $file ]
then
        echo 'File exists.'
else
        echo 'File does not exist.'
fi
Listing 6-19

prog18.sh

Run the script to see the output.

Summary

In this chapter, we have gotten started with shell scripts in the shell. As discussed earlier, shell scripts can be very useful tools for programmers who are tasked to complete various activities. We have explored shell scripts in quite detail. However, there is more to shell scripting than we have covered. If you are entrusted with tasks related to Unix-like systems, then you can use shell scripts at your work to get the desired results. Mastery in scripting requires a lot of practice in real-life tasks.

In the next chapter, we will explore I/O redirection techniques and learn about a useful utility known as crontab. We will demonstrate that with a real-life project.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.191.29.22