CSI110

 

Lecture 7

 

Writing C Shell Scripts (1)

• Apart from functioning as an interactive command interpreter, the shell also defines a simple programming language

• A program written in this language is known as a shell procedure or shell script

• When a file containing a script is executed, the shell performs all the tasks in the file as though they had been entered individually

• In their most basic form, they are useful for performing frequently used combinations of actions

• As the shell language also includes variables, control structures and input and output features, more complex programs are possible

 

Invoking Shell Scripts

• There are two ways in which a shell script can be executed

by direct interpretation

by indirect interpretation

• Invoking a shell script by direct interpretation

%babe> csh file [arg...]

which runs the file using the C Shell

• Invoking a shell script by indirect interpretation

Make the file readable and executable

Execute it

%babe> file [arg...]

• In either case, the shell script will run in a separate sub-shell

 

• Type pwd to display the name of the current directory

• Type the following into a file called try

cd /usr/lib

pwd

• Execute it using csh try

• Now type pwd again at the command line prompt

• Change try's permissions so you can execute it by typing

try

at the command line prompt

• Type pwd again at the command line prompt

• Why did we get this behaviour?

• We will discuss the relationship between the invoking shell and the invoked shell later

A Simple Example

• We're going to write a simple script to consult a database of users

• Copy the file users from /tmp into your current directory

• A script called find_user will contain a single line containing a search for a case insensitive occurrence of the first parameter given to find_user in users

Positional parameters from the command line can be referred to from inside a script using the $n symbol, where n is the parameter position

• If find_user is called with the parameter staff (find_user staff), then $0 is find_user and $1 is staff. $2 ... $m are set to null

• Write the script, set execution rights on it, and run it

• Usually, user scripts are stored in the directory ~/bin, which is also added to your command search path

• Create a new directory bin in your home directory and move find_user into it

• Edit your C Shell configuration file (.cshrc in your home directory), to add ~/bin to the path

• Does it matter where in the path ~/bin is added?

• Enter a new C Shell

• You will now be able to run find_user from anywhere

• If you add a new script to ~/bin during a C Shell, you will only be able to access it from anywhere in the current shell session if you run rehash

• If you run find_user staff again it will fail, because find_user and users are no longer in the same directory

• Move users to your home directory and modify the find_user script accordingly

• Do you need to run rehash again?

Shell Script Basics

• Filename extensions are not significant in UNIX

• So how does UNIX know how to execute a shell script?

• Executable files can be one of a number of types

• If the file starts with a magic number, then UNIX knows that it is a binary executable file

• Otherwise, if the first character in the file is not a #, UNIX treats it as a Bourne Shell (sh) script

• If it starts with a # and the second character is not !, then it is treated as a C Shell script

• If it starts with #!, then UNIX invokes the program following the #! as the program to use to interpret the rest of the file

• E.g., edit find_user, inserting #!/bin/csh as the first line, and re-run the program

• Now change the first line to read #!/bin/cat and re-run the program again

• Although executable files starting with # (and not #!) will invoke a C Shell, it is usually more efficient to use #!/bin/csh -f instead

• The -f option to csh prevents the .cshrc file from being loaded, which results in faster loading/execution times

• In the remainder of these lectures, a commandlist is a sequence of zero or commands seaparated by NEWLINE or semi-colon characters, and a wordlist is a list of zero or more blank separated words

Csh Positional Parameters

• Apart from using $0, $1, ..., $m to refer to positional parameters, you can also $argv[n]

• In addition, $#argv is the number of positional parameters, and $argv[*] is a wordlist of all parameters (excluding the command name!)

• Be aware that although $0 is the name of the command, $argv[0] is undefined!

• The equivalent of $argv[*] is $*

• Re-write find_user using the $argv[] notation instead of the $ notation

• In addition, use echo to print the number of arguments that find_user was called with

• Call find_user with no parameters

• Fix find_user so it prints an appropriate error message instead

 

The foreach command

foreachcontrol_variable (wordlist)

commandlist

end

• Modify find_user to accept an arbitrary number of positional parameters and to search users for each parameter

• If an * appears as the wordlist, then UNIX assumes it is a reference to a filename and performs filename expansion on it

• Write myls which lists the files in the current directory (use foreach and echo - do NOT simply call ls from within myls!)

• Modify myls to take an optional command line argument and list only the files starting with the argument

 

The if command

(1) if (expr) simple_command


(2) if (expr) then

commandlist1

[else

commandlist2]

endif


(3) if (expr1) then

commandlist1

else if (expr2) then

commandlist2]

[else

commandlist3]

endif

• First form

if ($#argv == 1) grep -i $argv[1] ~/users

• Second form

if ($#argv == 1) then

grep -i $argv[1] ~/users

else

echo usage: $0 name-to-find

exit(1)

endif

• Third form

if ($#argv < 1 || $#argv >2) then

echo usage: $0 '[from-file] to-file'

exit(1)

else if ($#argv == 2) then

@from = $argv[1]

@to = $argv[2]

else

@to = $argv[1]

endif

• There can be any number of else if constructs

• The @ symbol is used to enable numerical computation. The reserved word set can be used instead, e.g., set from = $argv[1]

exit(n) is used to force terminate execution of a script, returning control to the invoking script or shell

• If n is 0, then termination was normal

• If n != 0, then termination is abnormal, and the value of n indicates which error occurred

n is the exit status of the script

 

The switch command

• Multiway branching

switch (str)

case pattern1:

commandlist1

breaksw

case pattern2:

commandlist2

breaksw

...

default:

commandlist

endsw

The while command

while (expr)

commandlist

end

while ($#argv > 0)
grep -i $argv[1] ~/users
shift
end