Shell Script Writing

 

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 # (pound sign)

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.

 

ways to run a shell script

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. 

 

  1. Interpreted in the current shell

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.

 

  1. Interpreted in the indicated 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

 

  1. using the exec command

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

 

Arguments to a shell script

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