Introduction to Shell Scripts

What is a shell script?

A shell script is program written using Linux/UNIX shell commands.  They provide a method for us to group together shell commands into one single command.

A Simple Example

Create a file with the following in:


 
  #!/bin/csh

echo "Welcome to your first script "
echo -n "The time is "
date
echo "You are currently in the directory"
pwd

You need to make the file executable so type chmod +x myfirstscript

Now run the script by typing myfirstscriptand you show see output similar to this

Welcome to your first script
The time is Fri Sep 15 12:22:15 BST 2000
You are currently in the directory
/home/students/csai97/mer/public_html/crg/adv

Variables

Like other programming languages, shell scripts can use variables.  These can be created within the local scope of the script, or be externally defined.  When accessing the variable you need to place a $ symbol infront of the name.  For example this program uses the environment variable called USER to find out your username.


 
  #!/bin/csh

echo "This scripts uses variables"
echo -n "Your username is "
echo $user
echo -n "Your full name is " 
ypmatch $user passwd | cut -d: -f5 | cut -d, -f1

Chmod the file and then run

This scripts uses variables
Your username is mer
Your full name is Mark E Roberts

This next example creates and then prints a variable.  Notice how we can use the value of x inside the echo string.


 
  #!/bin/csh

echo "This scripts uses variables"
set x=4
echo "The value of x is $x"

This script uses variables
The value of x is 4
 

Programming Constructs

No programming language would be complete without some control over the flow of the program.  Csh has if...then...else constructs, while loops, for loops, switch statements.  This example demonstrates the use of if...then...else.  Note how the == is used as in C/C++/Java.

If...then...else

  #!/bin/csh

echo "This script uses an if statement"
if ( $user == "mer" ) then
    echo "Hello Mark"
else
    echo "You are not Mark you are"
    ypmatch $user passwd | cut -d: -f5 | cut -d, -f1
endif

Output

This scripts uses an if statement
Hello Mark
This scripts uses an if statement
You are not Mark you are
Joe T Bloggs

While loop

This example uses a while loop.  It will keep looping until the expression in brackets is false.  The value of X is decremented using the expr command.  This is done by means of command substitution. 


 
  #!/bin/csh

echo "This scripts uses an while loop"
set x=10
while ( $x > 0 ) 
    echo "The value of x is $x"
    set x = `expr $x - 1`
end

Output
This scripts uses an while loop
The value of x is 10
The value of x is 9
The value of x is 8
The value of x is 7
The value of x is 6
The value of x is 5
The value of x is 4
The value of x is 3
The value of x is 2
The value of x is 1

For loop

This example shows a for loop.  It shows how to iterate through a string varible and use the result in another command.


 
  #!/bin/csh

echo "This scripts uses an for loop"
set SERVERS="tinky-winky preston gromit"
foreach MACHINE ($SERVERS)
    echo "The following users are logged onto $MACHINE"
    rsh $MACHINE w -h | awk '{print $1}' | sort -u
end

Output
This scripts uses an for loop
The following users are logged onto tinky-winky
mer
msc11rxm
msc21jlc
msc42mag
msc46xxw
msc69kwc
msc86cic
msc86jkb
The following users are logged onto preston
msc17iel
msc42mag
msc43mnh
ug52slh
The following users are logged onto gromit
msc86wxr

Switch

This example show a number of things as well as the switch statement.  The statement $?REMOTEHOST tests for the existence of a variable.  In the G10 case we show how to use command substitution and a pipe to the wc program to work out the size of the print queue.  The use of the breaksw command is very important as without it the program flow would continue to the best option.  This code also uses comments.  The # symbol makes the shell ignore everything after it.


 
  #!/bin/csh

echo "This scripts uses an switch statement"

# Work out where we actually are

# If the REMOTEHOST variable is defined then that
# where we are.  Otherwise the hostname command
# will report the location.
if ( $?REMOTEHOST) then 
    set mac=$REMOTEHOST
else
    set mac=`hostname`
endif

# Locate the machine we are on
set loc=`locate $mac | cut -d' ' -f4 | cut -d: -f1`


 

switch ($loc)
    case "G12":
        set nearest="lw-g12"
        breaksw
    case "G10":
        # Two printers in this room.  Find the one
        # with the smallest queue
        set asize=`lpq -Plw-g10a | wc -l`
        set bsize=`lpq -Plw-g10b | wc -l`
        if ( $asize > $bsize )then
            set nearest="lw-g10b"
        else
            set nearest="lw-g10a"
        endif
        breaksw
    case "G13":
        set nearest="lw-g13"
        breaksw
    case "G3":
        set nearest="lw-g3"
        breaksw
endsw

echo "You are in $loc.  The best printer for you to use is $nearest"

Output
This scripts uses an switch statement
You are in G13.  The best printer for you to use is lw-g13

Arguments

The arguments given to a script are put into the numbered variables $0,$1,$2,...$n.  This example shows how we can use them and how we can check there are the right amount using the variable #argv which contains the number of arguments.  Here we also use the test command to check whether the file exists.  The different tests available are shown in the table below.


 
  #!/bin/csh

if ( $#argv != 2 ) then
    echo "Wrong number of arguments"
    echo "Usage: $0 filename number"
    exit 1
endif

if ( -f $1 ) then
    echo "File already exists"
else
    set counter="1"
    echo "Numbers 1 to $2" > $1
    while ( $counter <= $2 )
       echo -n "$counter " >> $1
       set counter = `expr $counter + 1`
    end
endif

Output
args_example thisfile 10
more testfile
 Numbers 1 to 10
 1 2 3 4 5 6 7 8 9 10
 

Test commands

The following switches can be used in test commands


 
Expression Result
-r filename True if the filename exists and is readable
-w filename True if the filename exists and is writable
-x filename True if the filename exists and is executable
-f filename True if the filename exists and is a regular file
-d filename True if the filename exists and is a directory
-h filename True if the filename exists and is a symbolic link
-c filename True if the filename exists and is a character special file
-b filename True if the filename exists and is a block special file
-p filename True if the filename exists and is a named pipe
-u filename True if the filename exists and its set-user-id bit is set
-g filename True if the filename exists and its group-user-id bit is set
-k filename True if the filename exists and its sticky bit is set
-s filename True if the filename exists and has a size greater than 0
file1-nt file2 True if file1 is newer than file2
file1-ot file2 True if file1 is older than file2
file1-ef file2 True if file1 and file2 are the same file
-z string True if the length of the string is 0
-n string True if the length of the string is > 0
string1 = string2 True if string1 and string2 are identical
string1 != string2 True if string1 and string2 are not identical
string True if the string is not NULL
string1 < string2 True if string 1 is alphabetically before string2
string1 > string2 True if string 1 is alphabetically after string2
n1 -eq n2 True if the integers n1 and n2 are algebraically identical
n1 -ne n2 True if the integers n1 and n2 are notalgebraically identical
n1 -gt n2 True if the integer n1 is algebraically greater than the integer n2
n1 -ge n2 True if the integer n1 is algebraically greater than or equal to the integer n2
n1 -lt n2 True if the integer n1 is algebraically less than the integer n2
n1 -le n2 True if the integer n1 is algebraically less than or equal to the integer n2