Chapter 25
Deploying Bash Scripts

  • Objective 5.1: Given a scenario, deploy and execute basic bash scripts.

images Linux system administrators often need to perform the same tasks over and over, such as checking available disk space on the system or creating user accounts. Instead of entering multiple commands every time, you can write scripts that run in the shell to do these tasks automatically for you. This chapter explores how bash shell scripts work and demonstrates how you can write your own scripts to automate everyday activities on your Linux system.

The Basics of Shell Scripting

Shell scripting allows you to write small programs that automate activities on your Linux system. Shell scripts can save you time by giving you the flexibility to quickly process data and generate reports that would be cumbersome to do by manually entering multiple commands at the command prompt. You can automate just about anything you do at the command prompt using shell scripts.

The following sections walk through the basics of what shell scripts are and how to get started writing them.

Running Multiple Commands

So far in this book we’ve been entering a single command at the command prompt and viewing the results. One exciting feature of the Linux command line is that you can enter multiple commands on the same command line and Linux will process them all. Just place a semicolon between each command you enter:

$ date ; who
Thu Feb 20 19:20:06 EST 2019
rich     :0           2019-02-20 19:15 (:0)
$

The Linux bash shell runs the first command (date) and displays the output; then it runs the second command (who) and displays the output from that command immediately following the output from the first command. While this may seem trivial, this is the basis of how shell scripts work.

Redirecting Output

Another building block of shell scripting is the ability to store command output. Often, when you run a command, you’d like to save the output for future reference. To help with this, the bash shell provides output redirection.

Output redirection allows us to redirect the output of a command from the monitor to another device, such as a file. This feature comes in handy when you need to log data from a shell script that runs after business hours, so you can see what the shell script did when it ran.

To redirect the output from a command, you use the greater-than symbol (>) after the command and then specify the name of the file that you want to use to capture the redirected output. This is demonstrated in Listing 25.1.

Listing 25.1: Redirecting output to a file

$ date > today.txt
$ cat today.txt
Thu Feb 20 19:21:12 EST 2019
$

The example shown in Listing 25.1 redirects the output of the date command to the file named today.txt. Notice that when you redirect the output of a command, nothing displays on the monitor output. All of the text from the output is now in the file, as shown by using the cat command to display the file contents.

The greater-than output redirection operator automatically creates a new file for the output, even if the file already exists. If you prefer, you can append the output to an existing file by using the double greater-than symbol (>>), as shown in Listing 25.2.

Listing 25.2: Appending command output to a file

$ who >> today.txt
$ cat today.txt
Thu Feb 20 19:21:12 EST 2019
rich     :0           2019-02-20 19:15 (:0)
$

The today.txt file now contains the output from the original date command in Listing 25.1 and the output from the who command ran in Listing 25.2.

images In Linux, everything is a file, including the input and output processes of a command. Linux identifies files with a file descriptor, which is a non-negative integer. The bash shell reserves the first three file descriptors for input and output. File descriptor 0 is called STDIN and points to the standard input for the shell, which is normally the keyboard. File descriptor 1 is called STDOUT, which points to the standard output for the shell, typically the monitor. This is where the standard output messages go. File descriptor 2 is called STDERR, which is where the shell sends messages identified as errors. By default, this points to the same device as the STDOUT file descriptor, the monitor. You can redirect only the errors from your shell script to a separate file from the normal output by using 2> instead of the standard > output redirection character. This allows you to specify a separate file for monitoring error messages from commands.

Output redirection is a crucial feature in shell scripts. With it, we can generate log files from our scripts, giving us a chance to keep track of things as the script runs in background mode on the Linux system.

Piping Data

While output redirection allows us to redirect command output to a file, piping allows us to redirect the output to another command. The second command uses the redirected output from the first command as input data. This feature comes in handy when using commands that process data, such as the sort command.

The piping symbol is the bar (|) symbol, which usually appears above the backslash key on US keyboards. Listing 25.3 shows an example of using piping.

Listing 25.3: Piping command output to another command

$ ls | sort
Desktop
Documents
Downloads
Music
Pictures
Public
Templates
test.txt
today.txt
Videos
$

The output from the ls command is sent directly to the sort command as input, but behind the scenes. You don’t see the output from the ls command displayed on the monitor; you only see the output from the last command in the pipe line, which in this case is the sort command. There’s no limit on how many commands you can link together with piping.

images The >, >>, and | symbols are part of a group of characters often referred to as metacharacters. Metacharacters are characters that have special meaning when used in the Linux shell. If you need to use a metacharacter as a standard character (such as using the > character as a greater-than symbol in your output instead of as a redirect symbol), you must identify the metacharacter by either placing a backslash in front of it or enclosing the metacharacter in single or double quotes. This method is called escaping.

The Shell Script Format

Placing multiple commands on a single line, by using either the semicolon or piping, is a great way to process data but can still get rather tedious. Each time you want to run the set of commands, you need to type them all at the command prompt.

However, Linux allows us to place multiple commands in a text file and then run the text file as a program from the command line. This is called a shell script because we’re scripting out commands for the Linux shell to run.

Shell script files are plain-text files. To create a shell script file, you just need to use any text editor that you’re comfortable with. If you’re working from a KDE-based graphical desktop, you can use the KWrite program, or if you’re working from a GNOME-based graphical desktop, you can use the GEdit program.

If you’re working directly in a command-line environment, you still have some options. Many Linux distributions include either the pico or nano editor to provide a graphical editor environment by using ASCII control characters to create a full-screen editing window.

If your Linux distribution doesn’t include either the pico or nano editor, there is still one last resort: the vi editor. The vi editor is a text-based editor that uses simple single-letter commands. It’s the oldest text editor in the Linux environment, dating back to the early days of Unix, which may be one reason it’s not overly elegant or user-friendly.

Once you’ve chosen your text editor, you’re ready to create your shell scripts. First, for your shell script to work you’ll need to follow a specific format for the shell script file. The first line in the file must specify the Linux shell required to run the script. This is written in somewhat of an odd format:

#!/bin/bash

The Linux world calls the combination of the pound sign and the exclamation symbol (#!) the shebang. It signals to the operating system which shell to use to run the shell script. Most Linux distributions support multiple Linux shells, but the most common is the bash shell. You can run shell scripts written for other shells as long as those shells are installed on the Linux distribution.

After you specify the shell, you’re ready to start listing the commands in your script. You don’t need to enter all of the commands on a single line, Linux allows you to place them on separate lines. Also, the Linux shell assumes each line is a new command in the shell script, so you don’t need to use semicolons to separate the commands. Listing 25.4 shows an example of a simple shell script file.

Listing 25.4: A simple shell script file

$ cat test1.sh
#!/bin/bash
# This script displays the date and who’s logged in
date
who
$

The test1.sh script file shown in Listing 25.4 starts out with the shebang line identifying the bash shell, the standard shell in Linux. The second line in the code shown in Listing 25.4 demonstrates another feature in shell scripts. Lines that start with a pound sign are called comment lines. They allow you to embed comments into the shell script program to help you remember what the code is doing. The shell skips comment lines when processing the shell script. You can place comment lines anywhere in your shell script file after the opening shebang line.

images Notice in Listing 25.4 we used the .sh file name extension on the shell script file. While this is not required in Linux, it’s become somewhat of a de facto standard among programmers. This helps identify that the text file is a shell script that can be run at the command line.

Running the Shell Script

If you just enter a shell script file at the command prompt to run it, you may be a bit disappointed:

$ test1.sh
test1.sh: command not found
$

Unfortunately, the shell doesn’t know where to find the test1.sh command in the virtual directory. The reason for this is the shell uses a special environment variable called PATH to list directories where it looks for commands. If your local HOME folder is not included in the PATH environment variable list of directories, you can’t run the shell script file directly. Instead, you need to use either a relative or an absolute path name to point to the shell script file. The easiest way to do that is by adding the ./ relative path shortcut to the file:

$ ./test1.sh
bash: ./test1.sh: Permission denied
$

Now the shell can find the program file, but there’s still an error message. This time the error is telling us that we don’t have permissions to run the shell script file. A quick look at the shell script file using the ls command with the -l option shows the permissions set for the file:

$ ls -l test1.sh
-rw-r--r-- 1 rich rich 73 Feb 20 19:37 test1.sh
$

By default, the Linux system didn’t give anyone execute permissions to run the file. You can use the chmod command to add that permission for the file owner:

$ chmod u+x test1.sh
$ ls -l test1.sh
-rwxr--r-- 1 rich rich 73 Feb 20 19:37 test1.sh
$

The u+x option adds execute privileges to the owner of the file. You should now be able to run the shell script file and see the output:

$ ./test1.sh
Thu Feb 20 19:48:27 EST 2019
rich     :0           2019-02-20 19:15 (:0)
$

Now that you’ve seen the basics for creating and running shell scripts, the next sections dive into some more advanced features you can add to make fancier shell scripts.

Advanced Shell Scripting

The previous section walked through the basics of how to group normal command-line commands together in a shell script file to run in the Linux shell. We’ll add to that by showing more features available in shell scripts to make them look and act more like real programs.

Displaying Messages

When you string commands together in a shell script file, the output may be somewhat confusing to look at. It would help to be able to customize the output by separating it and adding our own text between the output from each listed command.

The echo command allows you to display text messages from the command line. When used at the command line, it’s not too exciting:

$ echo This is a test
This is a test
$

But now you have the ability to insert messages anywhere in the output from the shell script file. Listing 25.5 demonstrates how this is done.

Listing 25.5: Using the echo statement in a script

$ cat test1.sh
#!/bin/bash
# This script displays the date and who’s logged in
echo The current date and time is:
date
echo
echo "Let’s see who’s logged into the system:"
who
$ ./test1.sh
The current date and time is:
Thu Feb 20 19:55:44 EST 2019

Let’s see who’s logged into the system:
rich     :0           2019-02-20 19:15 (:0)
$

The shell script shown in Listing 25.5 adds three echo commands to the test1.sh script. Notice that the first echo command doesn’t use any quotes, but the third one does. The reason for that is the text output from the third echo command contains single quotes. The single quote is also a metacharacter in the shell, which will confuse the echo command, so you need to place double quotes around the text. Also notice that the second echo command doesn’t have any text on the line. That outputs a blank line, which is useful when you want to separate output from multiple commands.

Using Variables

Part of programming is the ability to temporarily store data to use later in the program. You do that by using variables.

Variables allow you to set aside locations in memory to temporarily store information and then recall that information later in the script by referencing the variable name.

There are two types of variables available in the Linux shell. The following sections explain how to use both types in your shell scripts.

Environment Variables

Environment variables track specific system information, such as the name of the system, the name of the user logged into the shell, the user’s user ID (UID), the default home directory for the user, and the search path the shell uses to find executable programs. You can display a complete list of active environment variables available in your shell by using the set command, as shown in Listing 25.6.

Listing 25.6: Using the set command

$ set
BASH=/bin/bash
BASHOPTS=checkwinsize:cmdhist:complete_fullquote:expand_aliases:extglob:extquote
:force_fignore:histappend:interactive_comments:progcomp:promptvars:sourcepath
BASH_ALIASES=()
BASH_ARGC=()
BASH_ARGV=()
BASH_CMDS=()
BASH_COMPLETION_VERSINFO=([0]="2" [1]="8")
BASH_LINENO=()
BASH_SOURCE=()
BASH_VERSINFO=([0]="4" [1]="4" [2]="19" [3]="1" [4]="release" [5]="x86_64-pc-lin
ux-gnu")
BASH_VERSION=’4.4.19(1)-release’
CLUTTER_IM_MODULE=xim
COLORTERM=truecolor
COLUMNS=80
DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus
DESKTOP_SESSION=ubuntu
DIRSTACK=()
DISPLAY=:0
EUID=1000
GDMSESSION=ubuntu
...

There are environment variables that track just about every feature of the command-line shell. You can tap into these environment variables from within your scripts by using the environment variable name preceded by a dollar sign, as shown in Listing 25.7.

Listing 25.7: The test2.sh shell script file to display environment variables

$ cat test2.sh
#!/bin/bash
# display user information from the system.
echo User info for userid: $USER
echo UID: $UID
echo HOME: $HOME
$

The $USER, $UID, and $HOME environment variables are commonly used to display information about the logged-in user. If you run the test2.sh shell script shown in Listing 25.7, the output should look like this:

$ chmod u+x test2.sh
$ ./test2.sh
User info for userid: rich
UID: 1000
HOME: /home/rich
$

The values you see should be related to your user account. This allows you to dynamically retrieve information about the user account running your shell script to customize the output.

User Variables

User variables allow you to store your own data within your shell scripts. You assign values to user variables using the equal sign. Spaces must not appear between the variable name, the equal sign, and the value. Here are a few examples:

var1=10
var2=23.45
var3=testing
var4="Still more testing"

The shell script automatically determines the data type used for the variable value. Variables defined within the shell script are called local variables and are accessible only from within the shell script. Global variables are defined outside of the shell script at the main shell level and are inherited by the script shell environment.

images The set command displays all of the global variables set. If you need to see the local variables set for your session, use the printenv command. The export command allows you to mark a variable as exportable, which means any child processes spawned from your shell will see it. Finally, the env command allows you to run a script and modify environment variables internal to the script without affecting the system environment variables.

Just as with environment variables, you can reference user variables using the dollar sign. Listing 25.8 shows an example of writing a shell script that uses user variables.

Listing 25.8: Using user variables in a shell script

$ cat test3.sh
#!/bin/bash
# testing variables
days=10
guest=Katie
echo $guest checked in $days days ago
$

Running the test3.sh script from Listing 25.8 produces the following output:

$ chmod u+x test3.sh
$ ./test3.sh
Katie checked in 10 days ago
$

After you store the data in a user variable, you can reference it anywhere in your shell script!

images Be careful when using variables within the echo statement. Since variable names are just text values, if you try to append text to a variable name, the shell will consider the text as part of the variable name and you won’t get the results you thought. If you need to do that, you can enclose the variable name in braces, such as ${guest}. This ensures that any text appended to the end of the variable will be separate from the variable name.

Command-Line Arguments

One of the most versatile features of shell scripts is the ability to pass data into the script when you run it. This allows you to customize the script with new data each time you run it.

One method of passing data into a shell script is to use command-line arguments. Command-line arguments are data you include on the command line when you run the command. Just start listing them after the command, separating each data value with a space, in this format:

command argument1 argument2 ...

You retrieve the values in your shell script code using special numeric positional variables. Use the variable $1 to retrieve the first command-line argument, $2 the second argument, and so on. Listing 25.9 shows how to use positional variables in your shell script.

Listing 25.9: Using command-line arguments in a shell script

$ cat test4.sh
#!/bin/bash
# Testing command line arguments
echo $1 checked in $2 days ago
$ chmod u+x test4.sh
$ ./test4.sh Barbara 4
Barbara checked in 4 days ago
$ ./test4.sh Jessica 5
Jessica checked in 5 days ago
$

The test4.sh shell script uses two command-line arguments. The $1 variable holds the name of the person, and the $2 variable holds the number of days ago they checked in. When you run the test4.sh shell script, be sure to include both data values in the command line. The shell won’t produce an error message if a positional variable doesn’t exist; you just won’t get the results you expected:

$ ./test4.sh rich
rich checked in days ago
$

It’s up to you to check if the positional variable exists within your program code. We’ll explore how to do that later when we discuss logic statements.

The Exit Status

When a shell script ends, it returns an exit status to the parent shell that launched it. The exit status tells us if the shell script completed successfully or not.

Linux provides us with the special $? variable, which holds the exit status value from the last command that executed. To check the exit status of a command, you must view the $? variable immediately after the command ends. It changes values according to the exit status of the last command executed by the shell:

$ who
rich     :0           2019-02-20 23:16 (:0)
$ echo $?
0
$

By convention, the exit status of a command that successfully completes is 0. If a command completes with an error, then a positive integer value appears as the exit status.

You can change the exit status of your shell scripts by using the exit command. Just specify the exit status value you want in the exit command:

$ /bin/bash
$ exit 120
exit
$ echo $?
120
$

In this example we started a new child shell with the /bin/bash command and then used the exit command to exit the child shell with an exit status code of 120. Back in the parent shell, we then displayed the $? variable value to see if it matched what we had set in the exit command. As you write more complicated scripts, you can indicate errors by changing the exit status value. That way, by checking the exit status, you can easily debug your shell scripts.

Writing Script Programs

So far we’ve explored how to combine regular command-line commands within a shell script to automate common tasks that you may perform as the system administrator. But shell scripts allow us to do much more than just that. The bash shell provides more programming-like commands that allow us to write full-fledged programs within our shell scripts, such as capturing command output, performing mathematical operations, checking variable and file conditions, and looping through commands. The following sections walk through some of the advanced programming features available to us from the bash shell.

Command Substitution

Quite possibly one of the most useful features of shell scripts is the ability to store and process data. So far we’ve discussed how to use output redirection to store output from a command to a file and piping to redirect the output of a command to another command. There’s another technique, however, that can give you more flexibility in storing and using data in your scripts.

Command substitution allows you to assign the output of a command to a user variable in the shell script. After the output is stored in a variable, you can use standard Linux string manipulation commands (such as sort or grep) to manipulate the data before displaying it.

To redirect the output of a command to a variable, you need to use one of two command substitution formats:

  • Placing backticks (ˋ) around the command
  • Using the command within the $() function

Both methods produce the same result—redirecting the output from the command into a user variable. Listing 25.10 demonstrates using both methods.

Listing 25.10: Demonstrating command substitution

$ var1=ˋdateˋ
$ echo $var1
Fri Feb 21 18:05:38 EST 2019
$ var2=$(who)
$ echo $var2
rich :0 2019-02-21 17:56 (:0)
$

The output from the command substitutions is stored in the appropriate variables. You can then use those variables anywhere in your script program as a standard string value.

images The backtick character is not the same as a single quote. It’s the character usually found on the same key as the tilde character (~) on US keyboards. Because of the confusion between backticks and single quotes, it’s become more popular in the Linux world to use the $() function format.

Performing Math

Eventually you’ll want to do more than just manipulate text strings in your shell scripts. The world revolves around numbers, and at some point you’ll probably need to do some mathematical operations with your data. Unfortunately, this is one place where the bash shell shows its age. The mathematical features in the bash shell aren’t quite as fancy as the features found in newer shells, such as the Z shell. However, there are a couple of ways to use simple mathematical functions in bash shell scripts.

To include mathematical expressions in your shell scripts, you use a special format. This format places the equation within the $[] characters:

result=$[ 25 * 5 ]

You can perform lots of different mathematical operations on data using this method, but there is a limitation. The $[] format allows you to use only integers; it doesn’t support floating-point values.

If you need to do floating-point calculations, things get considerably more complicated in the bash shell. One solution is to use the bc command-line calculator program. The bc calculator is a tool in Linux that can perform floating-point arithmetic:

$ bc
bc 1.07.1
Copyright 1991-1994, 1997, 1998, 2000, 2004, 2006, 2008, 2012-2017 Free
 Software Foundation, Inc.
This is free software with ABSOLUTELY NO WARRANTY.
For details type ˋwarranty’.
12 * 5.4
64.8
3.156 * (3 + 5)
25.248
quit
$

Unfortunately, the bc calculator has some limitations of its own. The floating-point arithmetic is controlled by a built-in variable called scale. You must set this variable to the desired number of decimal places you want in your answers or you won’t get what you were looking for:

$ bc -q
3.44 / 5
0
scale=4
3.44 / 5
.6880
quit
$

To embed a bc calculation into your script, things get a bit complicated. You must use command substitution to capture the output of the calculation into a variable, but there’s a twist. The basic format you need to use is as follows:

variable=$(echo "options; expression" | bc)

The first parameter, options, allows us to set the bc variables, such as the scale variable. The expression parameter defines the mathematical expression to evaluate using bc. While this looks pretty odd, it works:

$ var1=$(echo "scale=4; 3.44 / 5" | bc)
$ echo $var1
.6880
$

This is not ideal, but it works for small projects. If you have a larger programming project that requires lots of calculations, we’d suggest looking into the Z shell. It supports lots of advanced mathematical functions and features.

Logic Statements

So far all of the shell scripts presented process commands in a linear fashion—one command after another. However, not all programming is linear. There are times when you’d like your program to test for certain conditions, such as if a file exists or if a mathematical expression is 0, and perform different commands based on the results of the test. For that, the bash shell provides logic statements.

Logic statements allow us to test for a specific condition and then branch to different sections of code based on whether the condition evaluates to a True or False logical value. There are a couple of different ways to implement logic statements in bash scripts.

The if Statement

The most basic logic statement is the if condition statement. The format for the if condition statement is as follows:

if [ condition ]
then
    commands
fi

If the condition you specify evaluates to a True logical value, the shell runs the commands in the then section of code. If the condition evaluates to a False logical value, the shell script skips the commands in the then section of code.

The condition expression has quite a few different formats in the bash shell programming. There are built-in tests for numerical values, string values, and even files and directories. Table 25.1 lists the different built-in tests that are available.

Table 25.1 Condition tests

Test Type Description
n1 -eq n2 Numeric Checks if n1 is equal to n2
n1 -ge n2 Numeric Checks if n1 is greater than or equal to n2
n1 -gt n2 Numeric Checks if n1 is greater than n2
n1 -le n2 Numeric Checks if n1 is less than or equal to n2
n1 -lt n2 Numeric Checks if n1 is less than n2
n1 -ne n2 Numeric Checks if n1 is not equal to n2
str1 = str2 String Checks if str1 is the same as str2
str1 != str2 String Checks if str1 is not the same as str2
str1< str2 String Checks if str1 is less than str2
str1> str2 String Checks if str1 is greater than str2
-n str1 String Checks if str1 has a length greater than zero
-z str1 String Checks if str1 has a length of zero
-d file File Checks if file exists and is a directory
-e file File Checks if file exists
-f file File Checks if file exists and is a file
-r file File Checks if file exists and is readable
-s file File Checks if file exists and is not empty
-w file File Checks if file exists and is writable
-x file File Checks if file exists and is executable
-O file File Checks if file exists and is owned by the current user
-G file File Checks if file exists and the default group is the same as the current user
file1 -nt file2 File Checks if file1 is newer than file2
file1-ot file2 File Checks if file1 is older than file2

Listing 25.11 shows an example of using if-then condition statements in a shell script.

Listing 25.11: if condition statements

$ cat test5.sh
#!/bin/bash
# testing the if condition
if [ $1 -eq $2 ]
then
   echo "Both values are equal!"
   exit
fi

if [ $1 -gt $2 ]
then
   echo "The first value is greater than the second"
   exit
fi

if [ $1 -lt $2 ]
then
   echo "The first value is less than the second"
   exit
fi
$

The test5.sh script shown in Listing 25.11 evaluates two values entered as parameters on the command line:

$ chmod u+x test5.sh
$ ./test5.sh 10 5
The first value is greater than the second
$

Only the command from the if statement that evaluated to a True logical value was processed by the shell script.

The case Statement

Often you’ll find yourself trying to evaluate the value of a variable, looking for a specific value within a set of possible values, similar to what we demonstrated in Listing 25.11. Instead of having to write multiple if statements testing for all of the possible conditions, you can use a case statement.

The case statement allows you to check multiple values of a single variable in a list-oriented format:

case variable in pattern1) commands1;; pattern2 | pattern3) commands2;;
*) default commands;;
esac

The case statement compares the variable specified against the different patterns. If the variable matches the pattern, the shell executes the commands specified for the pattern. You can list more than one pattern on a line, using the bar operator to separate each pattern. The asterisk symbol is the catchall for values that don’t match any of the listed patterns. Listing 25.12 shows an example of using the case statement.

Listing 25.12: The case statement

$ cat test6.sh
#!/bin/bash
# using the case statement

case $USER in
rich | barbara)
   echo "Welcome, $USER"
   echo "Please enjoy your visit";;
testing)
   echo "Special testing account";;
jessica)
   echo "Don’t forget to log off when you’re done";;
*)
   echo "Sorry, you’re not allowed here";;
esac
$ chmod u+x test6.sh
$ ./test6.sh
Welcome, rich
Please enjoy your visit
$

The case statement provides a much cleaner way of specifying the various options for each possible variable value. In the example shown in Listing 25.12, it checks for specific user accounts to output specific messages. If the user running the script is not one of those user accounts, it displays yet another message.

Loops

When you’re writing scripts, you’ll often find yourself in a situation where it would come in handy to repeat the same commands multiple times, such as applying a command against all of the files in a directory. The bash shell provides some basic looping commands to accommodate that.

The for Loop

The for statement iterates through every element in a series, such as files in a directory or lines in a text document. The format of the for command is as follows:

for variable in series ; do
   commands
done

The variable becomes a placeholder, taking on the value of each element in the series in each iteration. The commands can use the variable just like any other variable that you define in the script. Listing 25.13 shows how to use a for loop to iterate through all of the files in a directory.

Listing 25.13: Using the for loop

$ cat test7.sh
#!/bin/bash
# iterate through the files in the Home folder
for file in $(ls | sort) ; do
   if [ -d $file ]
   then
      echo "$file is a directory"
   fi
   if [ -f $file ]
   then
      echo "$file is a file"
   fi
done
$

If you run the test7.sh shell script, you should see a listing of the files and directories in your home directory:

$ ./test7.sh
Desktop is a directory
Documents is a directory
Downloads is a directory
Music is a directory
Pictures is a directory
Public is a directory
Templates is a directory
test1.sh is a file
test2.sh is a file
test3.sh is a file
test4.sh is a file
test5.sh is a file
test6.sh is a file
test7.sh is a file
today.txt is a file
Videos is a directory
$

That saves a lot of coding from having to check each file manually in a bunch of if or case statements.

images When working with files in a directory, it’s common to use wildcard characters to specify a range of files. There are three methods you can choose from:

A question mark (?) represents one character. Thus, c?t would match cat, cot, or cut.

An asterisk (*) represents any character, multiple characters, or even no characters. Thus, c*t would match cat, caveat, or ct.

A bracketed set of characters matches only the characters in the brackets. Thus, c[au]t would match cat and cut, but not cot.

This method of using wildcard characters for file names is also called file globbing and can be used in any situation where you iterate through multiple files.

The while Loop

Another useful loop statement is the while command. This is its format:

while [ condition ] ; do
   commands
done

The while loop keeps looping as long as the condition specified evaluates to a True logical value. When the condition evaluates to a False logical value, the looping stops. The condition used in the while loop is the same as that for the if statement, so you can test numbers, strings, and files. Listing 25.14 demonstrates using the while loop to calculate the factorial of a number.

Listing 25.14: Calculating the factorial of a number

$ cat test8.sh
#!/bin/bash
number=$1
factorial=1
while [ $number -gt 0 ] ; do
   factorial=$[ $factorial * $number ]
   number=$[ $number - 1 ]
done
echo The factorial of $1 is $factorial

The shell script retrieves the first parameter passed to the script and uses it in the while loop. The while loop continues looping as long as the value stored in the $number variable is greater than 0. In each loop iteration that value is decreased by 1, so at some point the while condition becomes False. When that occurs the $factorial variable contains the final calculation. When you run the test8.sh program, you should get the following results:

$ ./test8.sh 5
The factorial of 5 is 120
$ ./test8.sh 6
The factorial of 6 is 720
$

The while loop took all of the hard work of iterating through the series of numbers. Now you can plug any number as the command-line parameter and calculate the factorial value!

images The opposite of the while command is the until command. It iterates through a block of commands until the test condition evaluates to a True logical value.

Exercise 25.1 Writing a bash script to view the password information for system users

This exercise walks through how to write a bash script to view the password information for all user accounts configured on the Linux system.

  1. Log into your Linux graphical desktop and open a command prompt window.
  2. At the command prompt, open a text editor of your choice and create the text file pwinfo.sh by typing nano pwinfo.sh, pico pwinfo.sh, or vi pwinfo.sh.
  3. Enter the following code into the new text file:
    #!/bin/bash
    # pwinfo.sh - display password information for all users
    list=$(cut -d : -f 1 /etc/passwd)
    for user in $list ; do
        echo Password information for $user
        sudo chage -l $user
        echo "----------"
    done
    
  1. Save the file using the appropriate save command for your editor.
  2. Give yourself execute permissions to the file by typing chmod u+x pwinfo.sh.
  3. Run the shell script by typing ./pwinfo.sh.
  4. Enter your password at the sudo command prompt.
  5. You should see the chage password information listed for all of the user accounts configured on the system.

Summary

Basic shell scripting allows us to combine multiple commands to run them as a single command. You can use output redirection to redirect the output of a command to a file that you can read later, or you can use piping to redirect the output of one command to use as input data for another command.

When you add multiple commands to a text file to run, you must start the text file with the shebang line (#!), which identifies the Linux shell to use. You’ll also need to give yourself execute permissions to run the file by using the chmod command with the u+x option. You may also need to either specify the full path to the file when you run it from the command prompt or modify the PATH environment variable on your system so that the shell can find your shell script files.

The bash shell provides additional features that you can add to your shell script files to make them look more like real programs. The echo statement allows you to interject text output between the command outputs in the script to help modify the output your script produces. The shell also provides both environment and user variables that you can access from within your shell script. Environment variables allow you to retrieve information about the shell environment your script is running in, such as what user account started the shell and information about that user account. User variables allow you to store and retrieve data from within your script, making it act like a real program.

The bash shell also provides advanced programming features that you can use in your shell scripts. Command substitution allows you to capture the output from a command into a variable so you can extract information from the command output within your shell script. The bash shell supports rudimentary integer math operations but is not overly adept with handling floating-point numbers. You’ll need help from other programs such as the bc calculator to do that.

Finally, the bash shell supports some standard programming features such as if and case logic statements, allowing you to test numbers, strings, and files for specific conditions and run commands based on the outcome of those conditions. It also supports both for and while loops, which allow you to iterate through groups of data, processing each element within a set of commands. These features can help make your bash shell scripts perform just like a real program.

Exam Essentials

Describe how to link multiple command-line commands together in a shell script. The bash shell allows us to place multiple commands sequentially in a file and will then process each command when you run the file from the command line. The output from each command will appear in the command-line output.

Explain how you can handle data within a bash shell script. The bash shell provides two ways to handle data within commands. Output redirection allows you to redirect the output of a command to a text file, which you, or another command, can read later. Piping allows you to redirect the output of one command to use as the input data for another command. The output never displays on the monitor when you run the shell script; the data transfer happens behind the scenes.

Explain the type of data you can access from within a shell script. The bash shell provides access to environment variables, which contain information about the shell environment the script is running in. You can obtain information about the system as well as the user account that’s running the shell script. The shell script also has access to positional variables, which allow you to pass data to the shell script from the command line when you run the shell script.

Describe how you can manipulate output data from a command before you use it in another command within a shell script. Command substitution allows you to redirect the output of a command to a user variable in your shell script. You can then use standard Linux text processing commands to manipulate the data, such as sort it or extract data records from it, before redirecting the variable data to another command.

Describe how the bash shell performs mathematical operations. The bash shell uses the $[] symbol to define mathematical equations to process. The bash shell can only perform integer math, so this capability is somewhat limited.

Explain the different methods for implementing logic within a bash shell script. The bash shell supports both if statements and the case statement. They both allow you to perform a test on a numerical value, string value, or a file and then run a block of commands based on the outcome of the test.

Review Questions

  1. What character or characters make up the shebang used in Linux to define the shell used for a shell script?

    1. >>
    2. #!
    3. |
    4. >
    5. 2>
  2. Henry needs to store the output from his script into a log file that he can read later. What character or characters should he use to do that?

    1. >>
    2. #!
    3. |
    4. >
    5. 2>
  3. Jasmine has created a new bash shell script and wants to run it from the command line. What chmod permissions should she assign to the file to run it as a shell script?

    1. 644
    2. u+r
    3. u+x
    4. u+w
    5. u=wr
  4. What environment variable contains the username of the user who started the shell?

    1. $USER
    2. $UID
    3. $HOME
    4. $BASH
    5. $1
  5. Zuri is writing a bash shell script and needs to assign a number to a variable. How should he do that?

    1. var1=$(10)
    2. var1 = 10
    3. var1=10
    4. var1="10"
    5. var1=`10`
  6. Cameron is writing a bash shell script and needs to test if a file exists and that it’s a file. What line of code should he write to do that?

    1. if [ -e file ]
    2. if [ -f file ]
    3. if [ -d file ]
    4. if [ -x file ]
    5. if [ -w file ]
  7. What character or combination of characters do you use to redirect the output of one command to another command?

    1. >>
    2. #!
    3. |
    4. >
    5. 2>
  8. Christina is creating a bash shell script and wants to make the script return a value of 2 if it fails. What statement should she add to do that?

    1. #!
    2. $?
    3. $1
    4. exit
    5. while
  9. What command should you use to perform a command substitution to assign the output of a command to a variable in your shell script?

    1. >
    2. >>
    3. $[]
    4. |
    5. $()
  10. What command should you use to perform a mathematical operation in your shell script?

    1. >
    2. >>
    3. $[]
    4. |
    5. $()
..................Content has been hidden....................

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