Ch6_Linux Bash Shell
Ch6_Linux Bash Shell
1
IOS203_Ch6
Objectives
Upon completion of this unit, you should be able to:
Configure your working environment using variables and shell startup files;
Create functions and aliases;
Write, execute and debug scripts using shell-scripting language.
Keywords
Shell variables, shell functions, env, set, #!, PATH, alias, unalias, shift, read, test, &&, ||,
case, for, while, if ... then ... else … fi, until, /etc/profile, ~/.bash_profile, ~/.bash_login,
~/.profile, ~/.bash_logout, ~/.bashrc, /etc/bashrc, /etc/profile.d.
2
IOS203_Ch6
CentOS and most Linux systems use the bash shell by default; the bash shell is a program that
interprets user commands, which are either directly entered by the user, or which can be read
from a file called the shell script or shell program. Shell scripts are, not compiled but interpreted.
They are read by the shell line per line and the shell searches for those commands on the system
in order to pass them to the kernel. The kernel executes the commands and returns the results to
the shell which may display them on the terminal window. Another important task of the bash
shell is to provide a user environment, which can be configured individually using shell variables
stored in configuration files.
A variable is a label that has a value resident in memory and can be hold by a file stored on a hard
disk. It can be used in commands, shell scripts and applications. Shell variables are case sensitive
and must prefixed by the dollar sign ‘$’ when using their values. There are two types of shell
variables: local and environment. While local variables are used by the shell in which they are
created, the environment variables are inherited by child shells such as when a new shell is
launched after logging in using the bash command.
The following example shows you how to set and use a local variable:
When setting a variable, don’t add any spaces on either side of the ‘=’ sign. When executing the
echo $A command, the shell looks for a variable named like the string following the dollar sign and
replaces it with the value of the variable, or with nothing if the variable does not exist. In the
previous example, the shell replaces $A by 250 which is the variable value.
The bash shell replaces variables with their values in double quoted lines, but not in single quoted
lines:
The following table contains some common variables of the bash shell. While some variables are
initialized by the bash shell and can be reassigned by the user, other variables are read only, and
may not be set by the user (e.g., last six variables in the table).
Variable Description
PWD Current working directory
RANDOM Random number between 0 and 32767
SECONDS Number of seconds since the shell was started
BASH_VERSION Current bash version
3
IOS203_Ch6
Here are the values of some variables of the bash shell on my Centos Linux:
4
IOS203_Ch6
set command
This command, without arguments, lists both shell local variables and environment variables
associated with the shell. You can use set | less command line to see the shell variables as follows
in the example below (the result of the command is truncated):
Linux allows users to use the bash shell to create or modify an environment variable, and then all
commands started by the shell will inherit that variable. You can transform a shell variable into
an environment variable by using the export command.
env command
This command, without arguments, lists only variables which have been exported to the
environment. Here is an example of some environment variables shown as a result of executing
the env command:
5
IOS203_Ch6
The example below shows you how to export a bash variable to make it an environment variable:
PATH variable
This variable determines where the shell is looking for commands to execute; it contains a list of
directories, separated by colons.
Not all of the executable files are stored in directories that are listed by your PATH environment
variable. Just because a program resides outside of your path, it does not mean that you cannot
run it. However, you must specify the program using the absolute path to that program.
If you want the shell to look in the Shell_lang directory, then add “:/home/student/Shell_lang” at
the end of your PATH value as follows:
Now, you can run any script stored in that directory without need to use the absolute path to the
script.
Function definition
A function is a group of commands that are assigned a name. To execute this group of commands,
you simply call the function by its name as any other command. In the following example, we
define a function named Hello. When you call the function using its name, it writes a hello
message and then prints the date and time on the screen:
If you exit the session, and login again, you will get a message telling you that “Hello” is not found
when trying to execute the Hello function:
6
IOS203_Ch6
When you define a variable (or a function), it will reside in memory during the current session.
When logging out the session, the variable (or function) will be deleted. In order to make your
variables (or functions) available for next sessions, you should store them in files on the hard disk.
Aliases
Alias is like custom shortcut used to represent a command (or a set of commands) executed with
or without options. The ls command, for example, is not else than an alias.
The alias command shows on the screen a list of defined aliases on your profile:
You can use the alias command to create myls alias as follows:
The unalias command is used to remove entries from the current user's list of aliases:
7
IOS203_Ch6
After invoking the bash shell, shell startup files (also called shell-initializing files) are read. What
files are read depends upon whether the shell is invoked as an interactive or non-interactive [1].
While interactive shell is a shell that reads and writes to a user’s terminal, non-interactive shell is
a shell that is not associated with a terminal, like when executing a script. An interactive could be
login or non-login shell. An interactive login shell is invoked when a user login to the terminal
either remotely via ssh or locally, or when bash is launched with the --login option. An interactive
non-login shell is invoked from the login shell, such as when typing bash in the shell prompt or
when opening a new terminal tab on the GUI.
When bash is invoked as an interactive login shell, or as a non-interactive shell with the --
login option, it first reads and executes commands from the /etc/profile file, if that file exists.
After reading default global settings stored in the /etc/profile file, the bash shell looks in the user
home directory for ~/.bash_profile, ~/.bash_login, and ~/.profile files, in that order, and reads
and executes commands from the first readable file found.
The /etc/profile login shell file: it contains values of shell variables specifying all settings
of all users' environments such as: PATH, USER, MAIL, HOSTNAME, HISTSIZE and the
umask value. It contains settings of some other startup programs. It will also run the
scripts found in the /etc/profile.d directory.
The ~/.bash_profile login shell file: in this file, you can add individually extra configuration
options or change default settings:
The ~/.bash_login login shell file: this file contains specific settings that are normally only
executed in the absence of ~/.bash_profile.
The ~/.profile login shell file: in the absence of ~/.bash_profile and ~/.bash_login,
~/.profile is read. It can hold configurations similar to their contents. The ~/.profile file is
read by all shells, while ~/.bash_profile only by the bash shell.
8
IOS203_Ch6
The ~/.bash_logout: this is an individual login shell file; it contains specific instructions
executed automatically when a login shell exits. For example, it is useful if you want to
make backup of your files just before logging out.
The ~/.bashrc non-login shell file: you can use it to add individually extra configuration
options or change default global settings. You can add your private shell functions and
aliases.
The /etc/bashrc non-login shell file: it contains system-wide definitions for shell functions
and aliases. When the bash is invoked as an interactive non-login shell, it reads and
executes commands from this file if the file exists, and it is readable.
The /etc/profile.d directory: all readable scripts stored in this directory are read and
executed at startup; they do things like enabling color-ls, aliasing vi to vim, setting locales,
etc.
Login shells first call /etc/profile, which calls /etc/profile.d. Then, the file ~/.bash_profile is
called. This file, in turn, calls ~/.bashrc, which calls /etc/bashrc. Each script in turn can undo
changes made in previously called scripts.
Non-login shells first call ~/.bashrc. This calls /etc/bashrc, which calls /etc/profile.d.
Note: If any of the previous files does not found, you can create it.
A shell script is series of commands, functions or variables written in a text file, which could be
edited using text editors. It is just like batch files in MS-DOS, but more powerful and interpreted,
9
IOS203_Ch6
line-by-line, in the same way that you write the lines, one-by-one, in interactive shell. Then, that
file can be run as a command.
The first line in a shell script should identify the shell that’s used to interpret and run it, such as
the following:
#!/bin/bash
Shell scripting language uses the hash mark # as a comment character, so the script interpreter
ignores the words following this mark. The first two characters of a shell script #! are called “she-
bang” or magic number (sometimes called “sha-bang”) and cannot be a comment. In our example,
/bin/bash points to the bash shell, but you can use another shell, such as /bin/sh, /bin/tcsh or
/usr/bin/perl (used for Perl scripts).
After writing the shell script using a text editor (e.g., vi), you should modify its permissions to
make it executable. You do this with the chmod command as follows:
Then, you can type the script name preceded by ./ to tell the system to run the script in the current
directory.
You can also run the script by typing the shell name (i.e., bash) followed by the script name as:
When you need to run the script regularly, you can move it to a directory whose path exist in the
value of the PATH variable, such as /usr/local/bin. Thus, you can just type myscript.sh.
We can write a bash script that can accept arguments from the CLI as follows:.
To access these arguments, we can use the positional parameters ($1 to $9) in the script. Each
parameter corresponds to the position of the argument on the command line.
10
IOS203_Ch6
The first argument is read by the shell into the parameter $1, the second argument into $2, and
so on. After $9, you must enclose the arguments in brackets like ${10}, ${11}, and ${12}. The
following table contains common command line arguments:
shift command
In some shells, you cannot use brackets like ${10}. Therefore, to access parameters with numbers
greater than 9, you should use the shift command. In this case, $1 will be lost, $2 becomes $1, $3
becomes $2, and so on. The inaccessible 10th parameter becomes $9 and becomes accessible.
In order to debug your shell script, write set –x after the shebang line as follows:
#!/bin/bash
set –x # activate debugging from here
An alternative way to do the same thing is to write –x at the end of the shebang line:
You could also launch your scripts using the bash command with –x option:
When executing your script using debugging mode, each command will be preceded by a plus sign
‘+’.
You could write the set +x command to disable the debugging as follows:
You could, also, put set +x at the end of your script to disable the debugging mode.
Here is a shell script that helps you to understand the input arguments and the debugging mode:
#!/bin/bash
set -x
echo "your script is $0"
echo "hi $2"
echo "$#"
echo "$*"
11
IOS203_Ch6
echo "$@"
shift
echo "hi $2"
echo "$?"
echo "hi $2"
set +x
read command
This command asks for the user’s input and puts it in a variable. Here is a shell script showing you
how to use the read command:
#!/bin/bash
read -p "Enter a name: " name
echo "Hello $name"
echo "-----------------"
The option –p is used to display “Enter a name” to user, without a newline, before beginning to
read.
12
IOS203_Ch6
test command
This command test whether something is true or false. Here is an example showing how to use
the test command to testing whether 5 is greater than 22.
The test command returns 1 if the test fails, it returns 0 when a test succeeds.
This operator is used to chain commands together, such that the next syntax:
command2 is run if and only if the command1 exited without errors. More accurately, command1
exits with a return code of 0 (i.e., true).
|| control operator
This operator is used to chain commands together, such that the next syntax:
$ command1 || command2
command2 is run if and only if the command1 exited with errors. More accurately, exits with a
return code that does not equals to 0 (i.e., false).
You can replace the test command by square brackets. In the following examples, the first two
command lines are equivalent to the last two command lines.
String comparison
The following table shows you most common string comparisons:
13
IOS203_Ch6
[ -n string1 ] string1 has non zero length (contains one or more characters)
Numerical comparison
The following table shows you most common numerical comparisons:
File operators
The following table shows you most common file operators:
Operator Description
-a filename True if the file exists
-b filename True if the file exists and is a block special file (e.g.,/dev/sda or /dev/sda1)
-c filename True if the file exists and is a character special file (e.g.,/dev/tty1)
14
IOS203_Ch6
Boolean operators
The following table shows you most common boolean operators:
Operator Description
! This is logical negation. This inverts a true condition into false and vice versa.
-o This is logical OR. If one of the operands is true, then the condition becomes true.
This is logical AND. If both the operands are true, then the condition becomes true
-a
otherwise false.
if [ condition ]; then
block_of_statements1
else
block_of_statements2
fi
15
IOS203_Ch6
Here is a shell script showing you how to use the if conditional statement:
#!/bin/bash
if [ $# -ne 2 ]; then
echo "you must supply two arguments (strings)"
elif test $1 = $2
then
echo "The strings are matched"
else
echo "The strings are not matched"
fi
Note: In this script, a nested if statement (i.e., if ... then ... elif … then … fi) is used. You can add
many elif command statements before the final else statement. You should follow each elif by a
then statement.
case statement
This statement is similar to switch statement in C programming language. It can be used instead
of nested if statements to simplify complex conditionals when you have multiple different
choices; it has the following syntax:
case expression in
pattern_1)
block_of_statements1
;;
pattern _2)
block_of_statements2
16
IOS203_Ch6
;;
pattern _N)
block_of_statementsN
;;
*)
block_of_statements_Default
;;
esac
where the commands in the block_of_statements1 for the first match are executed, the
commands in the block_of_statements2 for the second match are executed, the commands in
the block_of_statementsN for the N match are executed. The commands in
the block_of_statements_Default are executed when no one of the previous blocks is executed.
The '|’ symbol can be used for separating multiple patterns, and the ‘)’ operator terminates a
pattern list. Each case plus its according commands are called a clause. Each clause must be
terminated with ‘;;’. Each case statement is ended with the esac word.
Here is a shell script showing you how to use the case conditional statement:
#!/bin/bash
echo -e "\n Command Menue \n"
echo "---------------"
echo "a. Current date and time"
echo "b. Users currently logged in"
echo "c. Name of the working directory"
echo -e "[0-9]. sleep for [0-9] seconds\n"
echo -e "Enter a,b, c or any digit: \c"
read answer
case "$answer" in
a)
date
;;
b)
who
;;
c)
pwd
;;
[0-9])
sleep $answer
;;
*)
echo "There is no selection: $answer"
esac
17
IOS203_Ch6
for loop
In the bash shell, the classical for loop has three syntaxes; we use them in the following script:
#!/bin/bash
for i in 1 2 3 #This is the first syntax
do
echo "Welcome $i time"
done
sleep 2
for ((i = 0 ; i <= 4 ; i++)) #This is the second syntax
do
echo "Welcome $i time"
done
echo "----------"
echo "break and continue"
for index in 1 2 3 4 5 6 7 #This is the third syntax
do
if [ $index -le 3 ]; then
echo "continue"
continue
fi
echo "$index"
if [ $index -ge 3 ]; then
echo "break"
break
fi
done
echo "The End"
18
IOS203_Ch6
Note: In the previous script, beak and continue are used. Those statements are used to stop a
loop or skip some of its iterations. The break statement is used to terminate the execution of the
entire loop. The continue statement is similar to the break command, except that it causes the
current iteration of the loop to exit, rather than the entire loop.
while loop
The while loop is used to execute a set of commands while some condition is true. Below a simple
script showing you how to use the while loop:
#!/bin/bash
tries=0
limits=5
input="hi"
while [ "$input" != "secret" ] && [ $tries -lt $limits ]
do
echo "Enter your passwd"
read input
tries=$(( $tries + 1))
done
if [ $input = "secret" ]
then echo "welcome"
else
echo "retry, limit $limits is reached"
fi
19
IOS203_Ch6
until loop
This loop is used when you need to execute a set of commands until a condition is true. Below a
simple script showing you how to use the until loop:
#!/bin/bash
secretname=jenny
name=noname
until [ $name = $secretname ]
do
echo -e "your guess: \c"
read name
done
Using functions
Below a simple script showing you how to define and use a function within a script:
#!/bin/bash
func() {
echo "date function";
date;
}
echo "this is first call"
func
sleep 3
echo "this is second call"
func
20
IOS203_Ch6
Below a simple script showing you how to define and use a function within a script:
#!/bin/bash
calsum() {
echo `expr $1 + $2`
}
z=`calsum $1 $2`
echo $z
Note: There must be spaces between the operators and the expressions. For example, 1+8 is not
correct; it should be written as 1 + 8.
21
IOS203_Ch6
Questions
1- What must the first word of the first line in an executable bash script?
a. ##bash
b. #!bash
c. !!/bin/bash
d. shebang /bin/bash
e. None of the above
2- What permission(s) must a user have in order to execute a shell script?
a. execute permission
b. write permission
c. read permission
d. a and c
e. All of the above
3- Write a shell script that asks for a filename. Verify existence of the file, then verify that you
own the file, and whether it is writable. If not, make it writable.
4- Write a shell script to count down from 10 to 1, and print the result on the screen
5- Write a shell script to count from 1 to 15, and print the result on the screen
6- Write a shell script that uses a while loop to count from 2 to 12.
7- Create a new user account as your SVU account, ex. abc_88888, and login with it to a machine
that has its host name like the username you created. (you should show how you changed the
hostname in your answer). When you login, you should have on the screen:
a. A welcome message like this: “Welcome abc_88888, today is ##-##-2020 at hh:mm”.
You should replace abc_88888 by your username and “##-##-2020 at hh:mm” by the
current date and time.
b. Your user information: your UID number and your login shell. Besides the previous
requirements, you should resize the console screen to 25x80 (25 lines and 80
columns).
8- Write a shell script that prints on the screen a welcome message. The message should contain
the statement “Good TIME Abc_88888”, where the word “TIME” should be replaced with
“morning”, “afternoon”, “evening” or “night” according to the system time (Morning hours
belong to [05 – 12[, afternoon hours belong to [21 – 17[, evening hours belong to [17 – 20[,
and night hours belong to [20 – 05[).
9- Write a shell script that adds the extension “.svu” to all the files stored in a given directory.
10- Write a shell script to read a number and print it in reverse order. If the number is missed, the
script displays an error message.
11- Write a shell script that will print the number of files and directories in the current directory.
It should not count files and directories whose names begin with a dot (“.”). The script should
just print a single number.
12- Give the code for a bash script that deletes files containing more than a given number of
bytes. Suppose that the script arguments are named sz, f1, f2, f3, ..., fn. Argument sz is the
size (number of bytes) and arguments f1 through fn are the file names. The script should
behave as follows:
a. If no arguments are given (i.e., sz is missing,) the script should write an error message
to stderr and exit with a non‐zero exit status.
b. If at least the first argument (sz) is present, the script should process each of the file
arguments f1 through fn in turn. For each file argument,
22
IOS203_Ch6
i. If the file does not exist or is not a regular file, then ignore that argument and
continue processing with the next file argument. Do not show any messages.
ii. If the file does exist and is a regular file (i.e., not a directory or some other
kind of special file), then if it contains more than sz bytes it should be deleted.
iii. If there are no file arguments (i.e., only sz is present), the script should
terminate without doing anything further.
Hint: wc –c, bash test condition -f.
13- Suppose we have a long text file named story.txt. Write a shell script that will print out to the
screen the first 5 lines and the last 3 lines of the story.txt file.
14- Write a shell script to validate password strength. Here are a few assumptions for the
password string.
a. Length – minimum of 8 characters.
b. Contain both alphabet and number.
c. Include both the small and capital case letters. If the password doesn’t comply with
any of the above conditions, then the script should report it as a “Weak Password”.
15- Write a script that receives four parameters(file names), and does the following tasks:
a. Output the four parameters in reverse order;
b. Check whether those files exist or not.
16- Write a script, using case statement, to perform basic Math operations such as:
+ addition
- subtraction
x multiplication
/ division
The name of the script must be “MathScript” which works as follows:
$ ./ MathScript 16 / 4
Check for correct arguments
17- Improve the previous script “MathScript” to test that the numbers are between 1 and 100,
exit with an error if necessary.
18- Improve the previous script “MathScript” to congratulate the user if the sum equals the
product.
19- Write a shell script that counts the number of files ending in .txt in the current directory.
20- Write a script to print on the screen the content of a given file from a given line number to a
next given number of lines. e.g., if we call this script “ContentScript” and run it as follows:
$ ContentScript 3 12 myf
The output should be the content of “myf” file from line 3 to line 14.
23
IOS203_Ch6
References
[1] https://linuxize.com/post/bashrc-vs-bash-profile/
24