Getting started with Shell Programming
In this tutorial you are introduce to shell programming, how to write script, execute them etc. We will getting started with writing small shell script, that will print Knowledge is Power on screen.
How to write shell script
Following steps required to write shell script
Here we are writing our first shell script. See the common vi command list, if you are new to vi.
Now we write our first script that will print "Knowledge is Power" on screen.
$ vi first.sh
|
After saving the above script, you can run the script as follows
$ ./first.sh
This will not run script since we have not set Execute permission for our script
first.sh; to do this type command
$ chmod 755 first.sh
$ ./first.sh
First screen will be clear, then Knowledge is Power is printed on screen.
Script Command | Meaning |
$ vi first.sh | Start vi editor |
# # My first shell script # |
# followed any text is considered as comment. Comment gives
more information about script, logical explanations etc. Syntax: # comment |
clear | clear the screen |
echo "Knowledge is Power" | To print message or variables contains
on screen, we use echo command, general form of echo command is as follows
syntax: echo "Message" |
How Shell Locates the file (My own bin directory to execute script)
Exercise
1) Now write following shell script and note
down the it's output.
$
vi ginfo # # # Script to print user information who currently login , current date & time # clear echo "Hello $USER" echo "Today is \c ";date echo "Number of user login : \c" ; who | wc -l echo "Calendar" cal exit 0 |
Sometimes to process our data/information, data must be kept in computers RAM memory. RAM memory is divided into small locations, and each location had unique number called memory location/address, which is used to hold our data. Programmer can give a unique name to this memory location/address called memory variable or variable (Its a named storage location that may take different values, but only one at a time).
In Linux (Shell), there are two types of variable
1) System variables - Created and maintained by Linux itself. This type of variable defined in CAPITAL LETTERS.
2) User defined variables (UDV) - Created and maintained by user. This type of variable defined in lower
letters.
You can see system variables by giving command like $ set, some of the important System variables are
System Variable | Meaning |
BASH=/bin/bash | Our shell name |
BASH_VERSION=1.14.7(1) | Our shell version name |
COLUMNS=80 | No. of columns for our screen |
HOME=/home/vivek | Our home directory |
LINES=25 | No. of columns for our screen |
LOGNAME=students | Our logging name |
OSTYPE=Linux | Our Os type |
PATH=/usr/bin:/sbin:/bin:/usr/sbin | Our path settings |
PS1=[\u@\h \W]\$ | Our prompt settings |
PWD=/home/students/Common | Our current working directory |
SHELL=/bin/bash | Our shell name |
USERNAME=vivek | User name who is currently login to this PC |
NOTE: Here 'value' is assigned to given 'variable name' and Value must be on right side = sign.
Example
$ no=10 # this is ok
$ 10=no # Error, NOT Ok, Value must be on right side of = sign.
To define variable called 'vech' having value Bus
$ vech=Bus
To define variable called n having value 10
$ n=10
Rules for Naming variable name (Both UDV and System Variable)
(1) Variable name must begin with Alphanumeric character or underscore character (_), followed by one or more Alphanumeric character. For e.g. Valid shell variable are as follows
HOME
SYSTEM_VERSION
vech
no
(2) Don't put spaces on either side of the equal sign when assigning value to variable.
For e.g.. In following variable declaration there will be no error
$ no=10
But here there will be problem for following
$ no =10
$ no= 10
$ no = 10
(3) Variables are case-sensitive, just like filename in Linux. For e.g.
$ no=10
$ No=11
$ NO=20
$ nO=2
Above all are different variable name, so to print value 20 we have to use $ echo $NO and
not any of the following
$ echo $no # will print 10 but not 20
$ echo $No # will print 11 but not 20
$ echo $nO # will print 2 but not 20
(4) You can define NULL variable as follows (NULL variable is variable which
has no value at the time of definition) For e.g.
$ vech=
$ vech=""
Try to print it's value $ echo $vech , Here nothing will be shown because variable has no value i.e. NULL variable.
(5) Do not use ?,* etc, to name your variable names.
How to print or access value of UDV (User defined variables)
To print or access UDV use following syntax
Syntax:
$variablename
For eg. To print contains of variable 'vech'
$ echo $vech
It will print 'Bus' (if previously defined as vech=Bus) ,To print contains of variable 'n'
$ echo $n
It will print '10' (if previously defined as n=10)
Caution: Do not try $ echo vech It will print vech instead its value 'Bus' and
$ echo n, It will print n instead its value '10', You must use $ followed by variable name.
Exercise
Q.1.How to Define variable x with value 10 and print it on screen.
Q.2.How to Define variable xn with value Rani and print it on screen
Q.3.How to print sum of two numbers, let's say 6 and 3
Q.4.How to define two variable x=20, y=5 and then to print division of x and y (i.e. x/y)
Q.5.Modify above and store division of x and y to variable called z
Q.6.Point out error if any in following script
$ vi variscript # # # Script to test MY knowledge about variables! # myname=Vivek myos = TroubleOS myno=5 echo "My name is $myname" echo "My os is $myos" echo "My number is myno, can you see this number" |
echo [options] [string, variables...]
Displays text or variables value on screen.
Options
-n Do not output the trailing new line.
-e Enable interpretation of the following backslash escaped characters in the strings:
\a alert (bell)
\b backspace
\c suppress trailing new line
\n new line
\r carriage return
\t horizontal tab
\\ backslash
For e.g. $ echo -e "An apple a day keeps away \a\t\tdoctor\n"
How to display color with echo, bold and blink effects, how to print text on any row, column on screen, click here for more!
Use to perform arithmetic operations.
Syntax:
expr op1 math-operator op2
Examples
$ expr 1 + 3
$ expr 2 - 1
$ expr 10 / 2
$ expr 20 % 3 # remainder read as 20 mod 3 and remainder is 2
$ expr 10 \* 3 # Multiplication use \* not * since its wild card
$ echo `expr 6 + 3`
For the last statement not the following points
(1) First, before expr keyword we used ` (back quote) sign not the (single quote i.e. ') sign.
Back quote is generally found on the key under tilde (~) on PC keyboard OR to the above of TAB key.
(2) Second, expr is also end with ` i.e. back quote.
(3) Here expr 6 + 3 is evaluated to 9, then echo command prints 9 as sum
(4) Here if you use double quote or single quote, it will NOT work
For e.g.
$ echo "expr 6 + 3" # It will print expr 6 + 3
$ echo 'expr 6 + 3' # It will work
See Parameter substitution - To save your time.
There are three types of quotes
Quotes | Name | Meaning |
" | Double Quotes | "Double Quotes" - Anything enclose in double quotes removed meaning of that characters (except \ and $). |
' | Single quotes | 'Single quotes' - Enclosed in single quotes remains unchanged. |
` | Back quote | `Back quote` - To execute command. |
Example
$ echo "Today is date"
Can't print message with today's date.
$ echo "Today is `date`".
Now it will print today's date as, Today is Tue Jan ....,Note that the `date` statement uses back
quote.
By default in Linux if particular command is executed, it return two type of values which is used to see whether command is successful or not.
(1)If return value is zero (0), command is
successful.
(2)If return value is nonzero , command is not successful or some sort of error
executing command/shell script.
This value is know as Exit Status of that command.
To determine this exit Status we use $? variable of shell.
For e.g.
$ rm unknow1file
It will show error as follows
rm: cannot remove `unkowm1file': No such file or directory
and after that if you give command
$ echo $?
it will print nonzero value to indicate error. Now give command
$ ls
$ echo $?
It will print 0 to indicate command is successful.
Exercise
Try the following commands and not down there exit status
$ expr 1 + 3
$ echo $?
$ echo Welcome
$ echo $?
$ wildwest canwork?
$ echo $?
$ date
$ echo $?
$ echon $?
$ echo $?
$? useful variable, want to know more such Linux variables click
here to explore them!
Use to get input (data from user) from keyboard and store (data) to variable.
Syntax: read variable1, variable2,...variableN
$ vi sayH # #Script to read your name from key-board # echo "Your first name please:" read fname echo "Hello $fname, Lets be friend!" |
Run it as follows
$ chmod 755 sayH
$ ./sayH
This script first ask you your name and then waits to enter name from the user, Then user enters name from keyboard (After giving name you have to press ENTER key) and
entered name through keyboard is stored (assigned) to variable fname.
Wild cards (Filename Shorthand or meta Characters)
Wild card /Shorthand | Meaning | Examples | |
* | Matches any string or group of characters. | $ ls * | will show all files |
$ ls a* | will show all files whose first name is starting with letter 'a' | ||
$ ls *.c | will show all files having extension .c | ||
$ ls ut*.c | will show all files having extension .c but file name must begin with 'ut'. | ||
? | Matches any single character. | $ ls ? | will show all files whose names are 1 character long |
$ ls fo? | will show all files whose names are 3 character long and file name begin with fo | ||
[...] | Matches any one of the enclosed characters | $ ls [abc]* | will show all files beginning with letters a,b,c |
Note:
[..-..] A pair of characters separated by a minus sign denotes a range.
Example
$ ls /bin/[a-c]*
Will show all files name beginning with letter a,b or c like
/bin/arch /bin/awk
/bin/bsh /bin/chmod
/bin/cp
/bin/ash /bin/basename
/bin/cat /bin/chown
/bin/cpio
/bin/ash.static
/bin/bash /bin/chgrp
/bin/consolechars /bin/csh
But
$ ls /bin/[!a-o]
$ ls /bin/[^a-o]
If the first character following the [ is a ! or a ^ ,then any character not enclosed is matched i.e. do not show us file name that beginning with
a,b,c,e...o, like
/bin/ps
/bin/rvi
/bin/sleep /bin/touch /bin/view
/bin/pwd
/bin/rview /bin/sort
/bin/true /bin/wcomp
/bin/red /bin/sayHello
/bin/stty /bin/umount /bin/xconf
/bin/remadmin /bin/sed
/bin/su /bin/uname /bin/ypdomainname
/bin/rm
/bin/setserial /bin/sync /bin/userconf /bin/zcat
/bin/rmdir /bin/sfxload
/bin/tar /bin/usleep
/bin/rpm /bin/sh
/bin/tcsh /bin/vi
Syntax:command1;command2
To run two command with one command line.
Examples
$ date;who
Will print today's date followed by users who are currently login. Note that You can't use
$ date who
for same purpose, you must put semicolon in between date and who command.
Command Line Processing
Now try following command (assumes that the file "grate_stories_of" is not exist on your
system)
$ ls grate_stories_of
It will print message something like - grate_stories_of: No such file or directory.
ls is the name of an actual command and shell executed this command when you type command at shell prompt. Now it creates one question What are commands? What happened when you type $ ls grate_stories_of ?
The first word on command line, ls, is name of the command to be executed.
Everything else on command line is taken as arguments to this command. For
e.g.
$ tail +10 myf
Here the name of command is tail, and the arguments are +10 and myf.
Exercise
Try to determine command and arguments from following commands
$ ls foo
$ cp y y.bak
$ mv y.bak y.okay
$ tail -10 myf
$ mail raj
$ sort -r -n myf
$ date
$ clear
Answer
Command | No. of argument to this command (i.e $#) | Actual Argument |
ls | 1 | foo |
cp | 2 | y and y.bak |
mv | 2 | y.bak and y.okay |
tail | 2 | -10 and myf |
1 | raj | |
sort | 3 | -r, -n, and myf |
date | 0 | |
clear | 0 |
NOTE: $# holds number of arguments specified on command line. And $* or $@ refer to all arguments
passed to script.
Why Command Line arguments required
Let's take rm command, which is used to remove file, But which file you want to remove and how you will
tail this to rm command (Even rm command does not ask you name of file that you would like to remove). So what we do is we write command as follows
$ rm {file-name}
Here rm is command and file-name is file which you would like to remove. This way you tail to rm command which file you would like to remove. So we are doing one way
communication with our command by specifying file-name. Also you can pass command line arguments to your script to make it more users friendly. But how we
access command line argument in our script.
Lets take ls command
$ ls -a /*
This command has 2 command line argument -a and /* is another. For shell script,
$ myshell foo bar
Shell Script name i.e. myshell
First command line argument passed to myshell i.e. foo
Second command line argument passed to myshell i.e. bar
In shell if we wish to refer this command line argument we refer above as follows
myshell it is
$0
foo it is $1
bar it is $2
Here $# (built in shell variable ) will be 2 (Since foo and bar only two Arguments), Please note
at a time such 9 arguments can be used from
$1..$9, You can also refer all of them by using $* (which expand to
`$1,$2...$9`)
Exercise
Try to write following for commands,
Shell Script Name ($0),
No. of Arguments (i.e. $#),
And actual argument (i.e. $1,$2 etc)
$ sum 11 20
$ math 4 - 7
$ d
$ bp -5 myf +20
$ ls *
$ cal
$ findBS 4 8 24 BIG
Answer
Shell Script Name | No. Of Arguments to script | Actual Argument ($1,..$9) | ||||
$0 | $# | $1 | $2 | $3 | $4 | $5 |
sum | 2 | 11 | 20 | |||
math | 3 | 4 | - | 7 | ||
d | 0 | |||||
bp | 3 | -5 | myf | +20 | ||
ls | 1 | * | ||||
cal | 0 | |||||
findBS | 4 | 4 | 8 | 24 | BIG |
For e.g. now will write script to print command ling argument and we will see how to access them
$ vi demo #!/bin/sh # # Script that demos, command line args # echo "Total number of command line argument are $#" echo "$0 is script name" echo "$1 is first argument" echo "$2 is second argument" echo "All of them are :- $* or $@" |
Run it as follows
Set execute permission,
$ chmod 755 demo
Run it & test it,
$ ./demo Hello World
If test successful, copy script to your own bin directory (Install script
for private use)
$ cp demo ~/bin
Check whether it is working or not (?)
$ demo
$ demo Hello World
NOTE After this, For any script you have to used above command, in sequence, I am not going to show you all of the
above for rest of Tutorial.
Mostly all command gives output on screen or take input from keyboard, but in Linux it's possible to send output to file or to read input from file.
For e.g.
$ ls command gives output to screen; to send output to file of ls command
give command
$ ls > filename. It means put output of ls command to filename.
There are three main redirection symbols >,>>,<
(1) > Redirector Symbol
Syntax: Linux-command > filename
To output Linux-commands result to file. Note that If file already exist, it
will be overwritten else new file is created. For e.g. To send output of ls
command give
$ ls > myfiles
Now if 'myfiles' file exist in your current directory it will be overwritten
without any type of warning.
(2) >> Redirector Symbol
Syntax: Linux-command >> filename
To output Linux-commands result to END of file. Note that If file exist , it
will be opened and new information/data will be written to END of file,
without losing previous information/data, And if file is not exist, then new
file is created. For e.g. To send output of date command to already exist file
give command
$ date >> myfiles
(3) < Redirector Symbol
Syntax: Linux-command < filename
To take input to Linux-command from file instead of key-board. For e.g. To take
input for cat command give
$ cat < myfiles
Click here to learn more about I/O Redirection
You can also use above redirectors simultaneously as follows
Create text file sname as follows
$cat > sname
vivek
ashish
zebra
babu
Press CTRL + D to save.
Now issue following command.
$ sort < sname > sorted_names
$ cat sorted_names
ashish
babu
vivek
zebra
In above example sort command takes input from sname file and output of sort
command (i.e. sorted names) is redirected to sorted_names file.
Now try following command
$ tr "[a-z]" "[A-Z]" < sname
> cap_names
$ cat cap_names
VIVEK
ASHISH
ZEBRA
BABU
Here tr command is used to translate all lower case characters to upper-case letters. It take input from sname file, and tr's output is redirected to cap_names file.
:-) Now try following command and find out most important point
$ sort > new_sorted_names < sname
$ cat new_sorted_names
Pips
A pipe is a way to connect the output of one program to the input of another
program without any temporary file.
Command using Pips | Meaning or Use of Pipes |
$ ls | more | Here the output of ls command is given as input to more command So that output is printed one screen full page at a time |
$ who | sort | Here output of who command is given as input to sort command So that it will print sorted list of users |
$ who | sort > user_list | Same as above except output of sort is send to (redirected) user_list file |
$ who | wc -l | Here output of who command is given as input to wc command So that it will number of user who logon to system |
$ ls -l | wc -l | Here output of ls command is given as input to wc command So that it will print number of files in current directory. |
$ who | grep raju | Here output of who command is given as input to grep
command So that it will print if particular user name if he is logon or
nothing is printed (To see particular user is logon or not) |
If a Linux command accepts its input from the standard input and produces its output on standard output is know as a filter.
A filter performs some kind of process on the input and gives output.
For e.g.. Suppose we have file called 'hotel.txt' with 100 lines data, And from 'hotel.txt' we would like to print contains from line number 20 to line number 30 and store this result to file called 'hlist' then give command
$ tail +20 < hotel.txt | head -n30 >hlist
Here head is filter which takes its input from tail command (tail command start selecting from line number 20 of given file i.e. hotel.txt) and passes this lines as input to head, whose output is redirected to 'hlist' file.
Now consider following example
$ sort < sname | uniq >
u_sname
Here uniq is filter which takes its input from sort command and passes this
lines as input to uniq; Then uniqs output is redirected to "u_sname"
file.
What
is Processes
Process is kind of program or task carried out by your PC.
For e.g.
$ ls -lR
ls command or a request to list files in a directory and all subdirectory in
your current directory. It is a process. A process is program (command given by
user) to perform specific Job. In Linux when you start process, it gives a
number (called PID or process-id), PID starts from 0 to 65535.
Why Process required
Linux is multi-user, multitasking Os. It
means you can run more than two process simultaneously if you wish. For e.g. To
find how many files do you have on your system you may give command like
$ ls / -R | wc -l
This command will take lot of time to search all files on your system. So you
can run such command in Background or simultaneously by giving command like
$ ls / -R | wc -l &
The ampersand (&) at the end of command tells shells start process (ls / -R
| wc -l) and run it in background takes next command immediately. An instance of
running command is called process and the number printed by shell is called
process-id (PID), this PID can be use to refer specific running process.
Linux Command Related with Process
For this purpose | Use this Command | Example |
To see currently running process | ps | $ ps |
To stop any process i.e. to kill
process |
kill {PID} | $ kill 1012 |
To get information about all running process | ps -ag | $ ps -ag |
To stop all process except your shell | kill 0 | $ kill 0 |
For background processing (With &, use to put particular command and program in background) | linux-command & | $ ls / -R | wc -l & |
NOTE that you can only kill process which are created by yourself. A Administrator can almost kill 95-98% process. But some process can not be killed, such as VDU Process.
Shells (bash) structured Language Constructs
if-then-fi for decision making is shell script
Before making any decision in Shell script you must know following things Type bc at $ prompt to start Linux calculator program
$ bc
After this command bc is started and waiting for your commands, i.e. give it some calculation as follows type 5 + 2 as
5 + 2
7
7 is response of bc i.e. addition of 5 + 2 you can even try
5 - 2
5 / 2
Now what happened if you type 5 > 2 as follows
5 > 2
0
0 (Zero?) is response of bc, How? Here it compare 5 with 2 as, Is 5 is greater then 2, (If I ask same question to you, your answer will be YES)
In Linux (bc) gives this 'YES' answer by showing 0 (Zero) value. It means when ever there is any type of comparison in Linux Shell It gives only two answer one is YES and NO is other.
Linux Shell Value | Meaning | Example |
Zero Value (0) | Yes/True | 0 |
NON-ZERO Value | No/False | -1, 32, 55 anything but not zero |
Expression | Meaning to us | Your Answer | BC's Response (i.e. Linux Shell representation in zero & non-zero value) |
5 > 12 | Is 5 greater than 12 | NO | 0 |
5 == 10 | Is 5 is equal to 10 | NO | 0 |
5 != 2 | Is 5 is NOT equal to 2 | YES | 1 |
5 == 5 | Is 5 is equal to 5 | YES | 1 |
1 < 2 | Is 1 is less than 2 | Yes | 1 |
$ cat > showfile #!/bin/sh # #Script to print file # if cat $1 then echo -e "\n\nFile $1, found and successfully echoed" fi |
Now run it.
$ chmod 755 showfile
$./showfile foo
Here our shell script name is showfile($0) and foo is argument (which is $1).Now we compare as follows
if cat $1 (i.e. if cat foo)
if cat command finds foo file and if its successfully shown on screen, it means our cat command is successful and its exist status is 0 (indicates success), So our if condition is also true and hence statement echo -e
"\n\nFile $1, found and successfully echoed" is proceed by shell. Now if cat command is not successful then it returns non-zero value (indicates some sort of failure) and this statement echo -e
"\n\nFile $1, found and successfully echoed" is skipped by our shell.
Exercise
Try to write answer for following
cat > trmif # # Script to test rm command and exist status # if rm $1 then echo "$1 file deleted" fi |
(Press Ctrl + d to save)
$ chmod 755 trmif
Now answer the following
A) There is file called foo, on your disk and you give command, $ ./trmfi foo what will be output.
B) If bar file not present on your disk and you give command, $ ./trmfi bar what will be output.
C) And if you type $ ./trmfi, What will be output.
For Answer click here.
test command or [ expr ] is used to see if an expression is true, and if it is true it return zero(0), otherwise returns nonzero(>0) for false.
Syntax: test expression
OR [ expression ]
Now will write script that determine whether given argument number is positive. Write script as follows
$ cat > ispostive #!/bin/sh # # Script to see whether argument is positive # if test $1 -gt 0 then echo "$1 number is positive" fi |
Run it as follows
$ chmod 755 ispostive
$ ispostive 5
Here o/p : 5 number is positive
$ispostive -45
Here o/p : Nothing is printed
$ispostive
Here o/p : ./ispostive: test: -gt: unary operator expected
The line, if test $1 -gt 0 , test to see if first command line argument($1) is greater than 0. If it is true(0) then test will return 0 and output will printed as 5 number is positive but for -45 argument there is no output because our condition is not true(0) (no -45 is not greater than 0) hence echo statement is skipped. And for last statement we have not supplied any argument hence error
./ispostive: test: -gt: unary operator expected is generated by shell , to avoid such error we can test whether command line argument is supplied or not.
test or [ expr ] works with
1.Integer ( Number without decimal point)
2.File types
3.Character strings
For Mathematics use following operator in Shell Script
Math- ematical Operator in Shell Script | Meaning | Normal Arithmetical/ Mathematical Statements | But in Shell | |
For test statement with if command | For [ expr ] statement with if command | |||
-eq | is equal to | 5 == 6 | if test 5 -eq 6 | if expr [ 5 -eq 6 ] |
-ne | is not equal to | 5 != 6 | if test 5 -ne 6 | if expr [ 5 -ne 6 ] |
-lt | is less than | 5 < 6 | if test 5 -lt 6 | if expr [ 5 -lt 6 ] |
-le | is less than or equal to | 5 <= 6 | if test 5 -le 6 | if expr [ 5 -le 6 ] |
-gt | is greater than | 5 > 6 | if test 5 -gt 6 | if expr [ 5 -gt 6 ] |
-ge | is greater than or equal to | 5 >= 6 | if test 5 -ge 6 | if expr [ 5 -ge 6 ] |
NOTE: == is equal, != is not equal.
For string Comparisons use
Operator | Meaning |
string1 = string2 | string1 is equal to string2 |
string1 != string2 | string1 is NOT equal to string2 |
string1 | string1 is NOT NULL or not defined |
-n string1 | string1 is NOT NULL and does exist |
-z string1 | string1 is NULL and does exist |
Shell also test for file and directory types
Test | Meaning |
-s file | Non empty file |
-f file | Is File exist or normal file and not a directory |
-d dir | Is Directory exist and not a file |
-w file | Is writeable file |
-r file | Is read-only file |
-x file | Is file is executable |
Logical Operators
Logical operators are used to combine two or more condition at a time
Operator | Meaning |
! expression | Logical NOT |
expression1 -a expression2 | Logical AND |
expression1 -o expression2 | Logical OR |
if condition then command1 if condition is true or if exit status of condition is 0(zero) ... ... else command2 if condition is false or if exit status of condition is (nonzero) ... ... fi
$ vi isnump_n #!/bin/sh # # Script to see whether argument is positive or negative # if [ $# -eq 0 ] then echo "$0 : You must give/supply one integers" exit 1 fi if test $1 -gt 0 then echo "$1 number is positive" else echo "$1 number is negative" fi |
Try it as follows
$ chmod 755 isnump_n
$ isnump_n 5
Here o/p : 5 number is positive
$ isnump_n -45
Here o/p : -45 number is negative
$ isnump_n
Here o/p : ./ispos_n : You must give/supply one integers
$ isnump_n 0
Here o/p : 0 number is negative
Here first we see if no command line argument is given then it print error message as
"./ispos_n : You must give/supply one integers". if statement checks whether number of argument ($#) passed to script is not equal
(-eq) to 0, if we passed any argument to script then this if statement is false and if no command line argument is given then this if statement is true. The echo command i.e.
echo "$0 : You must give/supply one integers"
| |
| |
1 2
1 will print Name of script
2 will print this error message
And finally statement exit 1 causes normal program termination with exit status 1 (nonzero means script is not successfully
run)
The last sample run $ isnump_n 0 , gives output as "0 number is negative", because given argument is not > 0, hence condition is false and it's taken as negative number. To avoid this replace second if statement with
if test $1 -ge 0.
Multilevel if-then-else
Syntax:
if condition then condition is zero (true - 0) execute all commands up to elif statement elif condition1 condition1 is zero (true - 0) execute all commands up to elif statement elif condition2 condition2 is zero (true - 0) execute all commands up to elif statement else None of the above condtion,condtion1,condtion2 are true (i.e. all of the above nonzero or false) execute all commands up to fi fiFor e.g. Write script as
$ cat > elf |
Try above script with
$ chmod 755 elf
$ ./elf 1
$ ./elf -2
$ ./elf 0
$ ./elf a
Here o/p for last sample run:
./elf: [: -gt: unary operator expected
./elf: [: -lt: unary operator expected
./elf: [: -eq: unary operator expected
Opps! a is not number, give number
Above program gives error for last run, here integer comparison is expected therefore error like "./elf: [:
-gt: unary operator expected" occurs, but still our program notify this thing to user by providing message
"Opps! a is not number, give number".
Loops in Shell Scripts
Computer can repeat particular instruction again and again, until particular condition satisfies. A group of instruction that is executed repeatedly is called a loop.
(a) for loop
Syntax:
for { variable name } in { list } do execute one for each item in the list until the list is not finished (And repeat all statement between do and done) doneExample of for loop
$ cat > testfor for i in 1 2 3 4 5 do echo "Welcome $i times" done |
Run it as,
$ chmod +x testfor
$ ./testfor
The for loop first creates i variable and assigned a number to i from the list of number from 1 to 5, The shell execute echo statement for each assignment of i. (This is usually know as iteration) This process will continue until all the items in the list were not finished, because of this it will repeat 5 echo statements.
Now try script as follows
$ cat > mtable #!/bin/sh # #Script to test for loop # # if [ $# -eq 0 ] then echo "Error - Number missing form command line argument" echo "Syntax : $0 number" echo "Use to print multiplication table for given number" exit 1 fi n=$1 for i in 1 2 3 4 5 6 7 8 9 10 do echo "$n * $i = `expr $i \* $n`" done |
Save and Run it as
$ chmod 755 mtable
$ ./mtable 7
$ ./mtable
For first run, Above program print multiplication table of given number where i = 1,2 ... 10 is multiply by given n (here command line argument 7) in order to produce multiplication table as
7 * 1 = 7
7 * 2 = 14
...
..
7 * 10 = 70
And for Second run, it will print message -
Error - Number missing form command line argument
Syntax : ./mtable number
Use to print multiplication table for given number
This happened because we have not supplied given number for which we want multiplication
table, Hence
script is showing Error message, Syntax and usage of our script. This is good idea if our program takes some argument, let the user know what is use of this script and how to used it. Note that to terminate our script we used 'exit 1' command which takes 1 as argument
(1 indicates error and therefore script is terminated)
(b)while loop
Syntax:
while [ condition ] do command1 command2 command3 .. .... done
$cat > nt1 #!/bin/sh # #Script to test while statement # # if [ $# -eq 0 ] then echo "Error - Number missing form command line argument" echo "Syntax : $0 number" echo " Use to print multiplication table for given number" exit 1 fi n=$1 i=1 while [ $i -le 10 ] do echo "$n * $i = `expr $i \* $n`" i=`expr $i + 1` done |
Save it and try as
$ chmod 755 nt1
$./nt1 7
Above loop can be explained as follows
n=$1 | Set the value of command line argument to variable n. (Here it's set to 7 ) |
i=1 | Set variable i to 1 |
while [ $i -le 10 ] | This is our loop condition, here if value of i is less than 10 then, shell execute all statements between do and done |
do | Start loop |
echo "$n * $i = `expr $i \* $n`" | Print multiplication table as 7 * 1 = 7 7 * 2 = 14 .... 7 * 10 = 70, Here each time value of variable n is multiply be i. |
i=`expr $i + 1` |
Increment i by 1 and store result to i. ( i.e. i=i+1) Caution: If we ignore (remove) this statement than our loop become infinite loop because value of variable i always remain less than 10 and program will only output 7 * 1 = 7 ... ... E (infinite times) |
done |
Loop stops here if i is not less than 10 i.e. condition of loop is not true. Hence |
(a) First, the variable used in loop condition must be initialized, then execution of the loop begins.
(b) A test (condition) is made at the beginning of each iteration.
(c) The body of loop ends with a statement that modifies the value of the test (condition) variable.
The case Statement
The case statement is good alternative to Multilevel if-then-else-fi statement. It enable you to match several values against one variable. Its easier to read and write.
Syntax:
case $variable-name in pattern1) command ... .. command;; pattern2) command ... .. command;; patternN) command ... .. command;; *) command ... .. command;; esacThe $variable-name is compared against the patterns until a match is found. The shell then executes all the statements up to the two semicolons that are next to each other. The default is *) and its executed if no match is found. For eg. Create script as follows
$ cat > car # # if no vehicle name is given # i.e. -z $1 is defined and it is NULL # # if no command line arg if [ -z $1 ] then rental="*** Unknown vehicle ***" elif [ -n $1 ] then # otherwise make first arg as rental rental=$1 fi case $rental in "car") echo "For $rental Rs.20 per k/m";; "van") echo "For $rental Rs.10 per k/m";; "jeep") echo "For $rental Rs.5 per k/m";; "bicycle") echo "For $rental 20 paisa per k/m";; *) echo "Sorry, I can not gat a $rental for you";; esac |
Save it by pressing CTRL+D
$ chmod +x car
$ car van
$ car car
$ car Maruti-800
Here first we will check, that if $1(first command line argument) is not given set value of rental variable to "*** Unknown vehicle ***",if value given then set it to given value. The $rental is compared against the patterns until a match is found.
Here for first run its match with van and it will show output For van Rs.10 per k/m.
For second run it print, "For car Rs.20 per k/m".
And for last run, there is no match for Maruti-800, hence default i.e. *) is executed and it prints, "Sorry, I can not gat a Maruti-800 for you". Note that esac is always required to indicate end of case statement.
How to de-bug the shell script?
While programming shell sometimes you need to find the errors (bugs) in shell
script and correct the errors (remove errors - debug). For this purpose you can
use -v and -x option with sh or bash command to
debug the shell script. General syntax is as follows
Syntax
sh option
{ shell-script-name }
OR
bash option { shell-script-name
}
Option can be
-v Print shell input lines as they are read.
-x After expanding each simple-command, bash displays the expanded value of PS4 system variable, followed by the command and its expanded arguments.
Examples
$ cat > dsh1.sh
#
# Script to show debug of shell
#
tot=`expr $1 + $2`
echo $tot
Press ctrl + d to save, and run it as
$ chmod 755 dsh1.sh
$ ./dsh1.sh 4 5
9
$ sh -x dsh1.sh 4 5
#
# Script to show debug of shell
#
tot=`expr $1 + $2`
expr $1 + $2
++ expr 4 + 5
+ tot=9
echo $tot
+ echo 9
9
See the above output, -x shows the exact values of variables (or statements are
shown on screen with values).
$ sh -v dsh1.sh 4 5
Use this to debug complex shell script.