sh Script Primer
For CS 32 Lab


Shebang         # and comments

Begin every sh script with the following shebang:

#!/bin/sh

Or '#!/bin/bash' is okay too. The shebang must be the very first line of the script, and without any spaces.

The pound sign, '#', actually denotes a comment. Except in the case of the shebang, the shell ignores the rest of any line with a pound sign.

Variables (and quotes)

All sh variables are treated as strings (but some commands may parse them as numbers).

User-defined variables

The assignment operator, '=' is used to initialize a variable, and this step also creates the variable. This operator must be used without any spaces before or after it, as in the following command that creates a variable named myname and assigns the string "Mike" to it:

myname="Mike"

After it is created, the variable is used by naming it with a '$' at the start, like the following command that prints (echoes) this name to the screen:

echo $myname

Often such a variable is printed as part of a message, and so it is enclosed in double quotes - which allow for text substitutions:

echo "My name is $myname. What is your name?"

If, for whatever reason, we don't want the text substitution to occur, then we use single quotes:

echo 'This prints $myname (the variable name, not its value).'

There is one other type of quotation mark used in scripts. Backquotes (a.k.a. grave accents) provide command substitution. Usually find it on the same key as the tilda ('~') in the upper left corner of most keyboards, or near the lower right on mini-keyboards. For example, the following command assigns the current working directory (as a string) to the new variable:

currentdir=`pwd`

Environment variables

Lots of variables are already available at the beginning of a script. Type 'env | more' at a shell prompt to get a list of some of them, along with their current values. Like all sh variables, you must start each environment variable name with a '$' to use it. For example, the following code prints the username of the current user:

echo "Your username is $USER"

Command line arguments are available as a list, beginning with $1, $2 and so on up to the total number of arguments - which is $#, by the way. Like command line arguments passed to a main function in C, these are strings, and $0 is the name of the script (as it is invoked at the prompt).

Control Structures

Several selection and iteration structures are available. Some basic structures are presented here.

Testing conditions

Most control structures rely on tests. These are boolean expressions either following the command test or enclosed in '[ ]' (square brackets). For example, if $value is equal to "100", then both of the following evaluate to true:

test $value -eq 100
 
[ $value -lt 200 ]

The second form requires spaces between the brackets and the expression. Also tests do not use the familiar relational operators like '==' and '<' to compare numbers. Instead, -eq means equals, -lt means less than, -le means less than or equal to, and so on. Here is an image of a table from Unix: The Textbook by Sarwar, et al. showing the various sh test operators. The table shows several of the test operators related to files too, but one other one that might help with the after-lab work is -e that tests if a file exists.

Selection

Mostly familiar, but also a bit weird in syntax, sh has if/else type structures. For example, the following code prints "Okay" only if a file named "xyz.dat" exists:

if [ -e "xyz.dat" ]
then
    echo "Okay"
fi

Here is a formal image of the if-fi structure, and here are images showing the syntax of if-else-fi and if-elif-else-fi structures. (Images are from the Sarwar et al. text.)

There is also a case structure - see the demo script named menu for an example.

Iteration

The sh for loop is for iterating over a list. Here is an image showing the for syntax and flow. The keywords do and done delimit the structure, just like the opening and closing curly braces ('{ }') of a C structure (and like the keywords then and fi of an sh if structure).

By default, the "list" used in the for structure is the list of command line arguments, $1 to $# - see the demo script named. echoargs for an illustration. But any list of strings will work. For example, the following code will print the contents of a user's current directory, because the asterisk ('*') is a wildcard character that expands to a list of files:

for item in *
do
    echo $item
done

Notice that a variable is created too - item in this example, and arg in the demo.

Other iteration structures are also available, including a while structure that relies on the same type of tests used in the if structures. Probably the for loop will suffice for Lab02 work though. And by the way, these control structures may be nested.


Back to Lab instructions

Prepared by Michael Costanzo.