Documents to read :
1. Manual of bash(1)
2. Advanced UNIX- A Programmer's Guide
By Stephen Prata
3. Bash-Prog-Intro-HOWTO
Convention: Words, such as file-names, commands etc, are put within
square brackets to separate them from lines of text. The square
brackets have no other meaning.
It is not possible to introduce shell programming is two or three
laboratory classes. You are requested to read manuals of [bash] or use
command [ $ info bash ] to know about all the features of [bash].
Login in your account. Create a directory named [shell1] in your home
directory. Carry out this experiment in that directory.
$ mkdir $HOME/shell
$ cd $HOME/shell/
Display the primary prompt string...
$ echo $PS1
Set a short primary prompt by changing the value of environmental
variable [PS1].
$ PS1="osl> "
Note: The prompt is changed for this session only. The original
primary prompt would be restored on next login. To make
the change for subsequent logins, set the variable [PS1]
in [/home/you/.bash_profile] file.
Some examples of redirection:
The CRT screen is the standard output and standard error. The command
osl> cat /etc/sh*
produces valid output and error output.
The error output can be redirected to [/dev/null], retaining the valid
output in standard output.
osl> cat /etc/sh* 2> /dev/null
The standard output can be redirected to a file and standard error can
go to standard error
osl> cat /etc/sh* > ./valid-output
Examine the file [valid-output]
osl> less ./valid-output
The standard output and standard error can be redirected to a file....
osl> cat /etc/sh* > ./valid-output-plus-error 2>&1
The above command is useful to catch large output, which is more than
one screen-full, such as compilation error of a C program.
Shell script:
This is a text file consisting of a number of shell
commands used to do a particular task.
Standard programming structures like variables, testing, functions,
loops, branching, arithmetic & logical operations etc etc... are
available in a shell script.
User created variables:
A variable may be created by using it. A value
may be assigned to a variable, by a statement of the form
name=value
No spaces are used on either side of [ = ] sign. If [ value ] is not
given, the variable is assigned the null string.
Letters, digits and underscore characters are allowed in variable
names and it must start with a letter or underscore character.
At this point one special shell variable( or parameter ) is introduced
to make the examples more useful. [ ? ] is that special parameter and
[ $? ] is the value of exit status of the last executed command. Zero
exit status indicates success.
Example:
Set a variable [outdoor_game] with value [foot-ball]
osl> outdoor_game=foot-ball
Print the exit status of the above command
osl> echo $?
It should be zero, indicating success.
Display the value of the variable
osl> echo $outdoor_game
Output should be [foot-ball]
Clear the variable
osl> unset outdoor_game
Display the value of the variable
osl> echo $outdoor_game
It should be null string. Null string is a valid value of a variable.
Try to use an illegal variable name
osl> outdoor-game=foot-ball
Ignore the output and print the exit status of the above command
osl> echo $?
It should be non-zero, indicating failure
The following is a simple shell script. Save the following lines in a
text file named [ f1 ]. Another special shell parameter, [ $ ] is
introduced in this example. [ $$ ] is the value of PID of the current
shell.
------------------------------------------------------------
#!/bin/bash
# file-name f1
# usage: program-name
# uncomment the following line to print commands and their
# arguments as they are executed.
#set -x
# variable [ college_name ] is initialised. Note
# absence of gaps on either side of equality sign
college_name=CEMK
# another variable is initialised using an existing variable
full_college_name=$college_name-KOLAGHAT
# the following variable is not initialised
# It is initialised with null string by shell
location=
# Variable [college_name] is printed
echo "College name is" $college_name
# following is formatted output
printf "College name is %s\n" $college_name
# Output is stored in an unique file, using
# current PID as file extension.
echo $full_college_name > name-of-college.$$
# another formatted output
printf "Full college name is %s and\n" $full_college_name
printf "is located in %s\n" $location
exit 0
------------------------------------------------------------
Assignment-1:
Execute the shell script..
osl> sh ./f1
Execute the shell script again. Two unique files should be created in
current directory with the two executions.
Initialise location=Mecheda and execute the shell script..
osl> sh ./f1
Try to execute the shell script as... ( it should fail )
osl> ./f1
Check the permission of the file with [ osl> ls -l ./f1 ]. To make the
shell script readable( 4 ) and executable ( 1 ), for the owner, use
[chmod] command
osl> chmod 0500 ./f1
Note: The file cannot be edited as write permission is absent.
Check the permission of the file with [ osl> ls -l ./f1 ]. Now execute
osl> ./f1
Remove the files generated by the above program...
osl> rm ./name-of-college.*
End of Assignment-1
Positional parameters:
A positional parameter is a parameter denoted by
one or more digits, other than the single digit 0.
Positional parameters are assigned from the shell's arguments, when it
is invoked, and may be reassigned using the [ set ] built-in command.
Example:
Save the following as file [f2]
------------------------------------------------
#!/bin/bash
# file-name f2
# usage: program-name arg1 arg2 arg3 arg4 ......
echo "Positional parameter one = " $1
echo "Positional parameter two = " $2
echo "Positional parameter three = " $3
echo "Positional parameter four = " $4
echo "Positional parameter five = " $5
echo "Program name is " $0
exit 0
------------------------------------------------
The above program illustrates that values are assigned to positional
parameters from the shell's arguments, when it is invoked. It also
shows that argument zero is program name.
Run the above program as...
osl> sh ./f2 cat dog horse pig
Record output:
Positional parameter one =
Positional parameter two =
Positional parameter three =
Positional parameter four =
Positional parameter five =
Note: Braces are required for positional parameter with more than one
digit.
Example:
osl> set a b c d e f g h i j k
osl> echo $11 # wrong
Output-> a1 # wrong
osl> echo ${11} # correct
Output-> k # correct
Example:
This program shows that values can be reassigned to the positional
parameters, using the [set] built-in command. It also shows that [set]
command has no effect on argument zero.
Save the following as file [f3]
------------------------------------------------
#!/bin/bash
# file-name f3
# usage: program-name arg1 arg2 arg3 arg4 ......
echo "Positional parameter one = " $1
echo "Positional parameter two = " $2
echo "Positional parameter three = " $3
echo "Positional parameter four = " $4
echo "Positional parameter five = " $5
echo "Program name is " $0
set mecheda bagnan nalpur dasnagar
echo "Positional parameter one = " $1
echo "Positional parameter two = " $2
echo "Positional parameter three = " $3
echo "Positional parameter four = " $4
echo "Positional parameter five = " $5
echo "Program name is " $0
exit 0
------------------------------------------------
Run the above program and record output
osl> sh ./f3 dolphin porpoise shark tuna
Positional parameter one =
Positional parameter two =
Positional parameter three =
Positional parameter four =
Positional parameter five =
Program name is
Positional parameter one =
Positional parameter two =
Positional parameter three =
Positional parameter four =
Positional parameter five =
Program name is
[shift] command:
This command is of the form [ shift n ]
[ shift 1 ] command shifts positional parameter 2 to positional
parameter 1, positional parameter 3 to positional parameter 2, and so
on. Positional parameter 1 is lost. Argument zero is not affected by
this command.
Another two special shell variables are introduced...
$# = Number of positional parameters
$* = The list of positional parameters
Save the following as [f4]
----------------------------------------------------
#!/bin/bash
# file-name f4
# usage: program-name arg1 arg2 arg3 arg4 ......
printf "Number of positional parameters are %u\n" $#
echo "Positional parameters are " $*
echo "Positional parameter one = " $1
echo "Positional parameter two = " $2
echo "Positional parameter three = " $3
echo "Positional parameter four = " $4
echo "Positional parameter five = " $5
echo "Program name is " $0
shift
echo "After one shift..."
printf "Number of positional parameters are %u\n" $#
echo "Positional parameters are " $*
echo "Positional parameter one = " $1
echo "Positional parameter two = " $2
echo "Positional parameter three = " $3
echo "Positional parameter four = " $4
echo "Positional parameter five = " $5
echo "Program name is " $0
exit 0
----------------------------------------------------
This program illustrates effect of [shift] command and values of [$#]
and [$*].
Run the program and record the output
osl> sh ./f4 11 22 33 44 55
Number of positional parameters are
Positional parameters are
Positional parameter one =
Positional parameter two =
Positional parameter three =
Positional parameter four =
Positional parameter five =
Program name is
After one shift command ...
Number of positional parameters are
Positional parameters are
Positional parameter one =
Positional parameter two =
Positional parameter three =
Positional parameter four =
Positional parameter five =
Program name is
Assignment-2:
The following commands are executed. What would be the
output of the last command ?
osl> set cat bat rat
osl> shift 1
osl> shift 1
osl> echo $*
Output-->
End of Assignment-2.
Command substitution:
The statements
$(command) and # newer syntax
`command` # note the back-quotes, older syntax
are used for command substitution. In command substitution the command
name is replaced by the output of the command.
Command substitution is used frequently in shell scripts.
Examples:
Run these commands
osl> echo "The date is" $( date "+%B %d %Y" ) # newer syntax
Output->
osl> echo "The date is" `date "+%B %d %Y"` # older syntax
Output->
You are asked to store the full name of the week in a variable
osl> your_variable=$( /bin/date +%A ); echo $your_variable
To understand the options of [date] command, read [ $ info date ]
A file is created with date of creation as file extension
osl> touch ./tempfile.$(date +%B-%d-%H-%M-%S)
Example:
Each file-name in a directory is to be stored in a separate
variable.
Find out path of the executable command [ls]
osl> whereis -b ls
Test the following command
osl> /bin/ls /etc
Set positional parameters with file-names, with command substitution
osl> set $( /bin/ls /etc )
Find out the number of positional parameters and record output
osl> echo $#
Output--> _____
List the positional parameters
osl> echo $*
Echo the 12th file-name
osl> echo ${12}
Example:
Each file name is to be stored sequentially in variables, in
ascending order of the size of the files. This might be done in the
following way...
Set the values of positional parameters with command substitution...
osl> set $( /bin/ls -S -r /etc )
You may read manual of [ls] for meaning of [-S] option.
Option [-r] reverses meaning.
Get number of positional parameters...
osl> echo $#
Output->
Let the output be 150
Output the name of largest sized file
osl> echo "The largest file is " ${150}
osl>
Output the name of smallest sized file
osl> echo "The smallest file is " $1
osl>
Save the following in a file [f5].
This program illustrates simple uses of environment variable [USER],
keyboard input with prompt, using a Unix command and processing its
output, from the shell script. The user must have read permission for
the file, as such checks are not incorporated in this shell script. It
is usual to provide such checks in robust shell scripts.
----------------------------------------------------------------------
#!/bin/bash
# file-name f5
# usage: program-name
echo "Dear $USER, give me the name of a file and I shall do the hard"
echo "work of counting number of newlines, number of words and number"
echo "of bytes in that file ! You must have read permission for it."
read -p "file-name please ? " file_naam
echo Number of lines, words and bytes are:
echo $(/usr/bin/wc -lwc $file_naam)
# the above line used command substitution
# Another way of processing the output of [wc] command. The positional
# parameters are reassigned with the output of [wc] command, with the
# help of [set] command and command substitution
set $(/usr/bin/wc -lwc $file_naam)
printf "file %s has %d lines, %d words and %d bytes\n" $4 $1 $2 $3
exit 0
----------------------------------------------------------------------
Run f5...
osl> sh ./f5
Use file-name [/etc/passwd], [ /var/log/lastlog ] or any other file you
can read.
Verify the result of the shell script with [wc] program using command
prompt
osl> wc file-name
[test] command:
Checks file types and compare values. [test] returns a
status of 0 (true) or 1 (false), depending on the evaluation of the
conditional expression.
A very brief summary of the options of [test] command are:
File type tests: -[bcdfhLpSt]
File access permission tests: -[gkruwxOG]
File characteristics tests: -e -s -nt -ot -ef
String tests: -z -n = !=
Numeric tests: -eq -ne -lt -le -gt -ge
Connectives for test: ! -a -o
You must read man [test(1)].
File [/etc/passwd] is readable by you. Run..
osl> test -r /etc/passwd; echo $?
Read the above test as "Is [/etc/passwd] file readable ?"
If the answer is "YES", the above command returns 0.
File [/etc/passwd] is not writable by you. Run..
osl> test -w /etc/passwd; echo $?
Read the above test as "Is [/etc/passwd] file writable ?"
If the answer is "NO", the above command returns 1.
The above command returns 1, meaning failure
[!] inverts meaning. Run...
osl> test ! -w /etc/passwd; echo $?
Read the above test as "Is [/etc/passwd] file not writable ?"
If the answer is "YES", the above command returns 0.
Store null string in a variable
osl> var=; echo $var
Double quotes in the following tests are used to allow character
substitution.
Test if it is a zero length string.
osl> test -z "$var"; echo $?
Read the above test as "Is var a zero length string ?"
Answer is "YES", exit status = 0
Test if it is a non-zero length string.
osl> test -n "$var"; echo $?
Exit status = 1
Initialise a variable and test if it is a non-zero length string
osl> another_var=xxx; echo $another_var; test -n $another_var; echo $?
exit status should be zero
Note: The test command occurs so frequently in shell scripts that
square brackets are used in place of test, for convenience.
Example: osl> [ -r /etc/hosts ]; echo $?
Conditional Execution:
Control operators && and || are used for
conditional execution.
osl> command1 && command2
In above [command2] is executed if and only if, [command1] returns an exit
status of zero.
osl> command1 || command2
In above [command2] is executed if and only if, [command1] returns a non
zero exit status.
You may read manual of [bash(1)] under CONDITIONAL EXPRESSIONS
Some examples:
The following command counts number of characters in the
file [/etc/hosts] if the file is readable...
osl> test -r /etc/hosts && wc -c /etc/hosts
The above command may be written as
osl> [ -r /etc/hosts ] && wc -c /etc/hosts
The first part of the next command returns a non zero exit status so the
second part is executed.
osl> [ -r /etc/shadow ] || echo "/etc/shadow is not readable"
The following command succeeds if file [ /etc/hosts ] is readable AND
the file [ /proc ] exists. Exit status of 0 indicates success. [a] is
logical AND operator.
osl> test -r /etc/hosts -a -e /proc ; echo $?
Exit status-->
The above command may be written as
osl> [ -r /etc/hosts -a -e /proc ] ; echo $?
The following command succeeds if file [ /etc/hosts ] is readable AND
the file [ /bogus ] exists. Non zero exit status indicates failure.
osl> [ -r /etc/hosts -a -e /bogus ] ; echo $?
Exit status-->
The following command succeeds if file [ /etc/bogus ] exists OR file
[ /bin ] ( a directory is a type of file ) exists. [ o ] is logical OR
operator.
osl> [ -e /etc/bogus -o -e /bin ]; echo $?
Exit status-->
The following command creates a file [xxx] in the current directory if
the file [yyy] does not exist in the current directory.
Remove file [ ./yyy ] if already present.
osl> rm ./yyy
Then execute the following command...
osl> [ -e ./yyy ] || touch ./xxx
Was a file [xxx] created in current directory ? ( Y / n )
Remove the file [ ./xxx ]
osl> rm ./xxx
Create a file [ ./yyy ] in current directory
osl> touch ./yyy
Run the command again
osl> test -e ./yyy || touch ./xxx
Was a file [ xxx ] created in current directory ? ( y / N )
[if] compound command:
if condition-1
then
1 \
2 | These commands are executed if
... | condition-1 is successful ( $? is 0 )
... /
elif condition-2
then
elf1 \
elf2 | These commands are executed if
... | condition-2 is successful
... /
else
1 \
2 | These commands are executed if
... | condition-1 and condition-2 both fail
... /
fi
There can be more than one [elif] block.
Arithmetic operations:
Some simple arithmetic operations are shown with
the following examples.
Old form of arithmetic evaluation
osl> a=4; b=7; echo `expr $a + $b`
11
Yet another form of arithmetic evaluation
osl> a=4; b=7; let c=( $a + $b ) ; echo $c
11
The above command is used, with spaces collapsed, in the following
two commands
osl> a=4; b=7; let c=($a + $b) ; echo $c
11
osl> a=4; b=7; let c=($a+$b) ; echo $c
11
Another form of arithmetic evaluation. We would be using this form for
the rest of of the experiment
osl> echo $(( 4+7 ))
osl> a=4; b=7; echo "Sum of a and b =" $(( $a + $b ))
Sum of a and b = 11
Unary minus and plus
osl> a=6; b=8; echo "Sum =" $(( +$a + -$b ))
Sum = -2
Multiplication
osl> a=12; b=5000; echo "Product of a and b =" $(( $a * $b ))
Product of a and b = _________
Exponentiation
osl> a=4; b=3; echo "Cube of $a =" $(( $a ** $b ))
Cube of 4 = ____
osl> a=2; b=10; echo $(( $a ** $b ))
output-->
Integer division
osl> a=36; b=5; echo "$a divided by $b =" $(( $a / $b ))
36 divided by 5 = ______
Remainder
osl> a=36; b=5; echo "Remainder =" $(( $a % $b ))
Remainder = __
Bitwise AND of two hexadecimal numbers
osl> a=0x0F; b=0x0C; echo "AND =" $(( $a & $b ))
AND = ___
Use this command to print value in hexadecimal
osl> a=0x0F; b=0x0C; AND=$(( $a & $b )); printf "AND = %X\n" $AND
Bitwise OR of two hexadecimal numbers
osl> a=0x0F; b=0x0C; echo "OR =" $(( $a | $b ))
OR = ___
Same as above command but display is in hexadecimal
osl> a=0x0F; b=0x0C; c=$(( $a | $b )); printf "OR = %X \n" $c
OR = __
Bitwise left shift by one
osl> num=0x0F; c=$(( $num <<>
___
Bitwise right shift by one
osl> num=0x0F; c=$(( $num >> 1 )); printf "%X\n" $c
___
The following example shows uses of some of the previous discussions.
Example:
Write a shell script which reads a directory name & compares
the files in the current directory, which has more files and how much
more files. ( WBUT2003 & WBUT2004 oslab )
----------------------------------------------------------------------
#!/bin/bash
# file-name f6
# usage: program-name
# check correct number of arguments
if test $# -ne 0
then
printf "usage: %s takes no argument\n" $0
exit 1
fi
# read the directory name
read -p "Directory name please ? " dir_name
# note that square brackets are used instead of the reserved word
# test
# is it not a directory ?
if [ ! -d $dir_name ]
then
echo $dir_name is not a directory
exit 1
fi
# is the directory not readable ?
if [ ! -r $dir_name ]
then
echo $dir_name does not exist / not readable
exit 1
fi
# the following is for debugging only. May be commented
echo "Directory name is " $dir_name
# reassign positional parameters with file-names of the directory.
# note the use of command substitution
set $( ls $dir_name )
# number of files in the directory are saved in an integer
# variable [ nof_dir ]
declare -i nof_dir=$#
# following line is for debugging only, may be commented
printf "Number of files in %s = %d \n" $dir_name $nof_dir
# set positional parameters with files of the current directory
set $( ls ./ )
# this set command replaces the previous set of positional parameters.
# number of files in the current directory are saved in
# an integer variable [ nof_c ]
declare -i nof_c=$#
# following line for debugging only, may be commented
printf "Number of files in current directory = %d \n" $nof_c
# An integer variable is initialised with zero
declare -i difference=0
if [ $nof_dir -gt $nof_c ]
then
echo $dir_name has more files than the current directory
difference=$(( $nof_dir - $nof_c ))
#let "difference=( $nof_dir - $nof_c )" # alternate form
#difference=`expr $nof_dir - $nof_c` # alternate form
echo $dir_name has $difference more files
elif [ $nof_c -gt $nof_dir ]
then
echo The current directory has more files than the $dir_name
difference=$(( $nof_c - $nof_dir ))
echo The current directory has $difference more files
elif [ $nof_c -eq $nof_dir ]
then
echo The current directory and $dir_name have same no. of files
fi
exit 0
----------------------------------------------------------------------
Test this program with wrong number of arguments. The program should
exit with usage message.
osl> sh ./f6 /etc/
Test this program with a file name which is not a directory
osl> sh ./f6
Directory name please ? /etc/hosts
Did it exit ? ( y / n )
Test this program with a valid, readable directory name and record
output
osl> sh ./f6
Directory name please ? /etc
Number of files in current directory = _____
Number of files in _________ = _____
[for] loops:
The general form of [for] loop in [bash]
for variable_name in value1 value2 value3...
do
commands
done
The values of the [for] loop can be supplied differently
[for] loop using explicitly given values:
Save the following as [f7a]
--------------------------------------------------
#!/bin/bash
# file-name f7a
# usage: f7a
# arguments are not checked to reduce size of file
for i in /etc/passwd /etc/hosts
do
echo $(/usr/bin/wc -lwc $i)
done
exit 0
--------------------------------------------------
Run the program as [ $ sh ./f7a ]
[for] loop using command line arguments:
A text file is to be sent to a number of users by email. The names of
the users are supplied as command line arguments.
-----------------------------------------------------
#!/bin/bash
# file-name f7b
#usage: f7b user1 user2
set -x
# argument checking is omitted to reduce size of file
for i in $*
do
mail -v $i@localhost < ./notice
done
exit 0
-----------------------------------------------------
To run the above program file [./notice] is to be created.
osl> nano notice
-------------------------------
Free coffee at Feluda's at 5 PM
-------------------------------
Run the above program as...
osl> sh ./f7b sumit you
For more flexibility, the name of the file is supplied as command line
argument.
-----------------------------------------------------
#!/bin/bash
# file-name f7c
#usage: f7c file-name user1 user2 .... ....
# argument checking is omitted to reduce size of file
# the file-name( 1st positional parameter) is saved
notice=$1
shift 1 # user1 is now the 1st positional parameter
# $*( list of parameters does not contain
# the file-name
for i in $*
do
mail -v $i@localhost < $notice
done
exit 0
-----------------------------------------------------
Change mode...
osl> chmod 0500 ./f7c
Run the program...
osl> ./f7c ./notice sumit guest root
In the following example, the values of [for] loop are generated with
command substitution.
Example:
Write a shell script, which reports names and sizes of all
files in a directory ( directory should be supplied as an argument to
the shell script ) whose size is exceeding 500 bytes. The file-names
should be printed in descending order of their sizes.( WBUT2004-oslab)
---------------------------------------------------------------------
#!/bin/bash
# file-name f8
# usage: program-name directory-name
# check correct number of arguments
if test $# -ne 1
then
printf "usage: %s directory-name\n" $0
exit
fi
# directory name is stored in a variable
dir=$1
# may be uncommented for debugging
# echo directory = $dir
# To make the program robust, the following checks can be made
# You should incorporate the checks
#1. Is it a directory ?
#2. Is it readable ?
# The following command lists the files( including directories ) in
# descending order of their sizes. Type [ $ info ls ] to understand
# [ -S ] option of [ls] command. The list is stored in a temporary
# file tmp.PID using redirection operator
ls -S $dir > tmp.$$
# an integer variable is cleared; clearing is not mandatory
declare -i size=0
# A parameter-list is created with the filenames of the directory
set $( cat ./tmp.$$ )
# The following [for] loop is executed for each file-name in that list
for i in $*
do
# echo file-name = $dir/$i # uncomment for debugging
if [ -d $dir/$i ]
then
echo $dir/$i is a directory
elif [ -f $dir/$i ]
then
set -- $( ls -l $dir/$i )
# the two hyphens are needed.
# Try the following two commands on command line
# set -- $( ls -l /etc/passwd )
# set $( ls -l /etc/passwd )
size=$5
# echo size is $size # uncomment for debugging
if [ $size -ge 500 ]
then
echo $dir/$i size=$size
fi
fi # end of elif block
done
# the temporary file is now deleted. The following line may be
# commented to examine the temporary file
/bin/rm ./tmp.$$
exit 0
---------------------------------------------------------------------
Change mode..
osl> chmod 0500 ./f8
Test with..
osl> ./f8 ./
osl> ./f8 /etc
[while] loop: It has a form
while condition
do
command1
command2
...
...
done
The commands between [ do ] and [ done ] are executed as long as the
[ condition ] returns a zero( successful) exit status.
[until] loop: It has the form
until condition
do
command1
command2
...
...
done
The commands between [ do ] and [ done ] are executed as long as the
[ condition ] returns a non-zero exit status.
[case] statement:
It has the form
case word in
pattern1 list1 of commands ;;
pattern2 list2 of commands ;;
pattern3 list3 of commands ;;
.
.
*) optional list of commands ;;
esac
A [case] command tries to match it against each pattern in turn. When
a match is found, the corresponding list of commands are executed.
After the first match, no subsequent matches are attempted. If none
match, the optional list of commands are executed.
The following example shows use of [until] loop, [while] loop, [case]
statement and simple arithmetic operation.
Example:
Write a shell script to make a password based menu driven
program, which will give three chances to enter the password in case
of wrong password, if it is correct then program will show the
i) no of users currently logged in
ii) calendar of current month
iii) date in date/month/yyyy format
iv) exit
(WBUT2004-oslab-11b)
-----------------------------------------------------------------
#!/bin/bash
# file-name f9
# usage: program-name
# check correct number of arguments
if test $# -ne 0
then
printf "usage: %s takes no argument \n" $0
exit
fi
secret=hajabarala # this is the password
input= # input is initialised with null string
declare -i count=0 # An integer variable is cleared
# read input till there is a match or 3 attempts are over
until ( [ "$input" = "$secret" -o $count -gt 2 ] )
do
# silent mode with [-s] option, typed passwords are not echoed
read -p "Password please ? " -s input
printf "\n" # line feed
# increment count
count=$(( $count + 1 ))
done
# If number of tries are exceeded OR match found, the execution
# comes here.
if [ "$input" != "$secret" ]
then
printf "Sorry $USER, %d tries are over :-(\n" $count
exit 1
else
printf "\a" # sound bell
echo Access granted to $USER, after $count try/tries
fi
# a menu is prepared
printf " i No. of users currently logged in \n"
printf " ii Calendar of current month \n"
printf " iii Date in date/month/yyyy format \n"
printf " iv Exit \n"
while ( : ) # endless loop
do
read -p "Enter choice " choice # read choice
case $choice in
i) n=$( who | wc -l ) # use this command in command line and
# check the output
printf "%d users are currently logged in \n" $n ;;
ii) month=$( date +%m )
year=$( date +%Y )
cal $month $year;;
iii) date=$( date +%d )
month=$( date +%m )
year=$( date +%Y )
echo "Date is" $date/$month/$year ;;
iv) exit 0 ;;
*) printf "Invalid choice\n" ;;
esac
done
exit 0
-----------------------------------------------------------------
Run the program
osl> sh ./f9
[select] statement:
This is of the form
select name [ in word ]
do
command
...
...
done
The [ word ] following [ in ] is expanded, generating a list of items.
The set of expanded words is printed on the standard error, each
preceded by a number. If the [ in word ] is omitted, the positional
parameters are printed. The PS3 prompt is then displayed and a line
is read from the standard input. If the line consists of a number
corresponding to one of the displayed words, then the value of [name]
is set to that word. The line read is saved in the variable REPLY. If
an invalid number is selected, name is set to null. The commands
between [ do ] and [ done ] are executed after each selection until a
break command is executed. For compete explanation read manual of
[bash(1)].
Example:
Write a shell script to check the entered file is a blank file
or not, if not blank then show the content of the file.
(WBUT2004-oslab)
In the above example the words "entered file" is changed to "selected
file", to illustrate [select] command
---------------------------------------------------------------------
#!/bin/bash
# file-name f10
# usage: f10
# Display a list of files from current directory
select file in $( ls ./ )
do
echo The item selected = $REPLY # for debugging; may be commented
echo "File is " ./$file # for debugging; may be commented
# test if the file size is greater than zero
if [ -s $file ]
then
cat $file
break
else
echo "File $file is blank"
fi
done
exit 0
---------------------------------------------------------------------
Change mode of the file...
osl> chmod 0500 ./f10
Create an empty file [kkk] in current directory...
osl> touch ./kkk
Test the above program with file [kkk]
osl> ./f10
-------------------------------------
Assignment-3:
Write the meaning of the flooding special parameters:
$? ->
$# ->
$0 ->
$* ->
$@ ->
$3 ->
Assignment-4:
Write a shell script to take two file-names as input and
if they are not duplicate file then concatenate them, otherwise delete
the second one. (WBUT2004-oslab)
Hint: Make a copy of an existing file in the current directory
osl> cp ./f10 ./f10-1
Read manual of [diff].
Examine output of the following command
osl> diff ./f10 ./f10-1; echo $?
Output->
In the shell script use
diff ./$1 ./$2 > /dev/null
To divert output from screen in case of mismatch.
$1 and $2 are command line arguments
Then test exit status of the above command
if [ $? -eq 0 ]
----------------------------------------
Optional Assignment-1.
Three variables are initialised
$ var1=xxx; var2=; var3=yyy; var4=xxx
Predict the output of the following commands and verify....
Test for non-zero length string
osl> test -n "$var1"; echo $? # output->
osl> [ -n "$var2" ]; echo $? # output->
Tests for zero length string
osl> test -z "$var1"; echo $? # output->
osl> [ -z "$var2" ]; echo $? # output->
Tests for string comparison
osl> [ "$var1" = "$var2" ]; echo $? # output->
osl> [ "$var1" = "$var3" ]; echo $? # output->
osl> [ "$var1" = "$var4" ]; echo $? # output->
osl> [ "$var1" != "$var4" ]; echo $? # output->
Hints: Read manual of [ bash(1) ] about [ /etc/profile ],
[~/.bash_profile ],[~/.bash_login], and [~/.profile]
Feedback:
Please point out mistakes and suggest which portions should
be removed, added, expanded etc etc.
