This shell-programming topic is a major portion
of this class. We will begin with an
introduction to shell programming in general.
We will then go to using the C-shell programming environment as the
programming environment because it is most closely related to the C language
and therefore may be the easiest to learn.
After, we will go to other shells to compare environments.
A shell script is a sequence of shell commands
in a single file that are then executed with one command. This is similar to the shell alias we looked
at last week, but different for two major reasons:
1)
The alias is held more like a variable in the current shell and accessed like a
variable when called upon while the shell script is actually kept in an ASCII
file.
2)
Because it is a file not associated with the current shell, it can usually be
used by any shell.
When talking about shell aliases we created an
alias similar to the following:
% alias
whoson 'who| grep jp'
Once this alias was available in the shell, we
could type the command
% whoson
and get exactly the same thing we would have
seen had we typed
% who | grep jp
Instead of creating a shell alias to do that
task, we can put the commands into a file that would look similar to the following
when displayed:
% more whoson.file
who | grep jp
Then we could run the file and it would do the
same thing as typing the command at the shell prompt.
Shell scripts can also have multiple lines. Then the shell commands listed would be done
in sequence.
for example:
Displaying the contents of the ASCII file
%
cat whoson
#!/bin/csh
date
who | grep jp
who | grep jf
%
Changing the permissions on that ASCII file
%
chmod u+x whoson
%
Running the ASCII file as a command found by the
command search path in the current working directory
% whoson
…OUTPUT
OF THAT SCRIPT
%
Running the ASCII file as a command if the
current working directory is not on your command search path
% ./whoson
…OUTPUT
OF THAT SCRIPT
%
The # has two very different independent
meanings.
Most of the time the # indicates that everything
that follows it (to the end-of-line character) is a comment to be ignored by
the shell interpreting the file.
If the # is the first character of the first
line in an executable shell script, it tells the shell which shell should be
used to interpret that file.
In the previous example,
#!/bin/csh
indicates that the c-shell kept in the /bin/
directory should be used if this is run as an executable file.
Use a # to cause the script to ignore the rest
of the line - comments to the person reading the source file.
There are many different ways to run a shell
script. The two columns show how it
would be done if the script named whoson was run from the c-shell prompt and
from the Bourne shell prompt.
1.
As a Command/Executable File
The most common is to make the shell script
executable and then just type its name to run it:
%
whoson $ whoson
To use this method, the file must be executable (chmod
permissions) and the first line should tell which shell is to be used to
interpret the commands. When a shell
script is run this way, it actually starts a child process to the current shell
which is a shell of the new type. The
purpose of that new shell is to run the shell script. Once the shell script is finished, the child shell
terminates.
Another
common way is to run the shell script interpreted by the current shell.
%
source whoson $ . whoson
The script commands will be executed within the
current shell (there would be no child process started). Notice the source command is used for
c-shell, and the Bourne shell uses the period (to mean the current shell). The script does not need to be made
executable since the current shell is already executing. The # as the first character of the first
line would be taken to indicate a comment since it is not an executable shell.
A third way to run a shell script is to
explicitly indicate what shell you would like to run as a child to interpret
the script. This is done by giving the
name of the shell as the command and the script's name as the argument to that
command. Notice here it is the name of
the shell (the command portion of the command line) which indicates which shell
should be used to interpret the script.
The #! if it appears as the first line is taken only to be a
comment. Since the type of child shell
is explicitly indicated by the command portion of the line, it doesn't matter
what type of a shell the parent is (a c-shell can start a script interpreted by
Bourne shell or vice-versa). The child
shell that is started exists only for the interpretation of the script and is
terminated as soon as the script completes.
%
csh whoson $ sh whoson
%
sh whoson $ csh whoson
The last method of calling is usually only used
from a shell script. This is because
the child shell started for the purpose of interpreting the script replaces the
current shell. (In other words the child replaces the parent.) This is a problem when it is run from the
shell prompt as shown here because the shell that produced the prompt (often
your login shell) is replaced by something that will terminate as soon as the
interpretation of the script is finished.
In other words, you would be logged out as soon as the script is
finished.
%
exec whoson $ exec whoson
The script commands will be executed within a
new shell of the same type as the current
shell, but when the shell completes, it will not come back to the current shell
Often when a shell script is called, you want to
be able to pass the script information as you call it. This is usually done when the script is
executable.
The arguments are automatically stored in an
array named argv.
The positions in the argv
array are numbered for access (the same as arrays in the C language).
Here is an example using the call to the script named thisscr
passing it four arguments. The
arguments are automatically stored in the array (you do not have to do anything
to indicate that).
%
thisscr one two 3 4
Inside of this script the following things are
true
The whole array contains the values in the order
they came in:
$argv
= one two 3 4
The * wildcard indicates all elements of the
array:
$argv[*]
= one two 3 4
The individual numbers can be used to indicate
individual elements:
$argv[1]
= one
$argv[4]
= 4
The 0th element of the array indicates the name
of the script (this one isn't available in all implementations of the shell).
$argv[0]
= thisscr
There is a shorter notation - to indicate each
element, you don't need to specify the argv array. It is assumed to be the default array so just using the index
number is permitted in most implementations.
$0
= thisscr
$2
= two
$3
= 3
The # is used to ask about the size of the
array. It tells how many elements are
currently stored in that array:
$#argv
= 4
$#
= 4
Another example using thisscr:
%
thisscr Bob Mike Jan
Inside of this script the following things are
true:
$argv
= Bob Mike Jan
$argv[*]
= Bob Mike Jan
$argv[1]
= Bob
$argv[2]
= Mike
$argv[0]
= thisscr
$0
= thisscr
$2
= Mike
$3
= Jan
$#argv
= 3
$#
= 3