Shell commands can be stored in a file which can be executed when required. A file containing shell commands is known as a script. For example:
% cat > list -create the filepwd ls ^D % chmod u+x list -give execute permission % list -execute the script /home/sunserv2_a/lnp5jb mbox message list bin
As mentioned earlier you are strongly recommended to carry out all shell programming in the Bourne Shell. This does not mean that you have to be running a Bourne Shell when you start a script. By default, all shell scripts are normally executed by the Bourne shell, whatever your normal interactive shell. This is possible because when you run a script a new shell is started ('spawned' according to the jargon) to run the commands. You can add (as the first line):
#! /bin/sh
to ensure that it is a Bourne Shell script. A C shell script would begin:
#! /bin/csh
The Bourne shell is capable of using parameters (see the section on parameters in the previous chapter.) These may be defined by the attribution operator =, by the read command and by the for command. The Bourne shell also interprets parameters which are given as arguments to the command that executes the shell script. Such parameters are 'positional parameters', which means that they are interpreted as a list structure. This can be seen in the simple example below:
% ex simple - first create the script "simple" [New file] :a echo $1 echo $2 echo $3 . :wq "simple" [New file] 3 lines, 24 characters % chmod u+x simple - make it executable % simple one two three - execute it one two three %
The three arguments given to the script ('one', 'two' and 'three') are read in by the script as variables named 1, 2 and 3, and so are referred to in the script as $1, $2 and $3 respectively. The special parameter * refers to all of the parameters, and the special parameter # refers to the number of parameters.
% ex simple2 - create a new script "simple2" [New file] :a echo $* echo $# :wq "simple" [New file] 3 lines, 51 characters % chmod u+x simple2 % simple2 one two three one two three 3 %
The read command enables parameter values to be entered interactively by the user while the script is running. It is usual to provide a prompt for the user, as in the script listed below (called greeting):
echo "What's your name?" read name echo "Hello, $name"
This can give the following results:
% greeting - execute the script What's your name? - output Jenny - the shell waits for your input Hello, Jenny - output%
More than one parameter can be given to the read command, usually separated by one or more spaces, as in the following script (called count):
echo How far can you count? read first second third echo $first $second $third
which can run to give the following:
% count How far can you count? 1 2 3 - user input 1 2 3 - script output
PRACTICE
See what happens with this script if you give it less than three parameters. Try it with more than three - is this what you expected? Can you explain this?
Try changing the script so that it echoes each parameter on a different line. This should show what is going on.
Sometimes it is useful to use control structures (like you find in programming languages), for example specifying that a command is only carried out under certain conditions, or that it does the same thing to a list of arguments. The shell provides control of flow with the following statements:
if structured control branching
case multiway branching
for looping over a list of commands
while conditional looping
until conditional looping
This structure allows conditional branching. It takes the following form:
if command_list_1 then command_list_2 [else command_list_3] -this clause is optional fi
Note that it is usual practice to indent the subordinate clauses, to make the script easier to read, but it is not necessary. This structure depends on the exit status of command_list_1. Every time a command runs it returns a 0 (also known as a 'true result') if it completes it's run successfully or a 1 ('false') if fails to end normally. The command_list_2 if and only if the exit status of the last command in command_list_1 is 0 (or true). The command_list_3 is executed if and only if the exit status of command_list_1 is 1 (or false).
The test command is often used to generate an exit result. Equivalence operators may also be used such as = (equals) or != (not equal to). The following example shows the script trio in action:
% cat trio if test $ = 3 then echo "There are three parameters." fi % trio one two three There are three parameters. % trio one two % - No output
The test command can be used in its simplest form to test if a string exists (more exactly, if it is a 'null string' or not), as in the following script:
% cat test.1 echo "Type something please:" read a if test $a then echo "Thank you" else echo "Thanks for nothing" fi % test.1 Type something please: Hello Thank you % test.1 Type something please: Thanks for nothing %
There are also several options that can be used in a command of the form:
test [options] filename
The following options are available:
-d true if a file is a directory
-h true if a file is a symbolic link
-x true if file exists and is executable
-l tests the length of a string
-f true if the file exists
-r true if the file can be read
-s true if the file exists and is not empty
-w true if the file can be written to
= is equal to
!= is not equal to
There are also the following arithmetic operators which apply to integer values:
-eq is equal to
-ne is not equal to
-gt is greater than
-ge is greater than or equal to
-lt is less then
-le is less than or equal to
Note that the above operators are all for use with the test command, and cannot be used independently.
When more than two directions for the control of flow are needed, if clauses may be nested, but the case structure provides a more elegant way of doing this. The case structure is of the form:
case string in pattern) command_list_1;; pattern) command_list_2;; -- -- pattern) command_list_N;; esac
The shell attempts to match the string with each pattern in turn. When a pattern that matches string is found, the appropriate command list is executed, and the case command is then terminated.
The case command is often used to give the user a choice of options, as in the following:
% cat pick echo "Type one of the following:" echo " 1 - who am I?" echo " 2 - who is logged on?" echo " 3 - date" echo " 4 - calendar" read n case $n in 1) whoami ;; 2) who ;; 3) date ;; 4) cal ;; esac
Study the following, rather more complex, example:
% cat test.2 echo "Give me a letter:" read letter case $letter in [aeiou]) echo "That's a vowel!";; [b-df-hj-np-tv-z]) echo "That's a consonant!";; [A-Z]) echo "I said lower case!";; [1-9]) echo "I said a letter, not a number!";; *) echo "What's that?" esac echo "Thank you and goodbye" % test.2 Give me a letter: a That's a vowel! Thank you and goodbye % test.2 x That's a consonant! Thank you and goodbye % test.2 ; What's that? Thank you and goodbye %
Note that the last pattern in this case clause will match anything if a match has not already been found.
The for command can be used to apply a list of commands to a series of variables. It has the general form:
for variable [in wordlist] do command-listdone
The wordlist is a series of strings separated by spaces. The variable takes the value of each of this strings consecutively and then runs the command list. Here is an example:
for n in one two three four five six seven do echo $n done
This script will output the list of words ('one', 'two', etc.)
The while command allows a sequence of commands to be executed repeatedly while certain conditions are met. It takes the form:
while command_list_1do command_list_2done
If command_list_1 is exited successfully, then command_list_2 is executed. This process continues until command_list_1 fails. Here is an example:
flag=y while test $flag = y do echo Do it again? read flag done
The loop will be repeated while the value of the variable flag remains 'y'.
The until command tests for the opposite condition to the while command. Command-list-1 is executed until command_list_2 fails. The following will do the same as the example with while above:
flag=y until test $flag = n do echo Do it again? read flag done
1. Write a script called hello which outputs the following:
your username
the time and date
who is logged on
Also output a line of asterices (*********) after each section.
2. Put the command hello into your .login file so that the script is executed every time that you log on.
3. Write a script that will count the number of files in each of your subdirectories.