Notes on the Bourne Shell: The Bourne shell was the original shell for UNIX. The bash shell is a newer version of the Bourne shell. To indicate that your shell program is to be run using the Bourne shell place the following on the first line: #! /bin/sh If you do not put /bin/sh, /bin/csh, or similar on the first line to indicate what shell to use, most systems will probably default to /bin/sh, the Bourne shell. On our Linux system /bin/sh is just a link to the bash shell. Use the following to get more complete information on this shell: man bash Note that you must have execute permission on in order to run a Shell script (or compiled program). For example, you might want to use permissions rwx------ for your scripts, so that you have read, write, and execute access. These permissions could be given to a file or files by using a command of the form: chmod 700 filename(s) For scripts that are made available to all users of a system one might use rwxr-xr-x, so that the owner (probably root) would have read, write, and execute access, but ordinary users would only have read and execute access. These permissions could be given to a file or files by using a command of the form: chmod 755 filename(s) The usual location for scripts that the system administrator wants to add to the system for all users to be able to access is the directory /usr/local/bin. The following is a very simple Bourne shell script. It just carries out two Linux commands. It is, however, safer to execute cleanup that to try entering a command like "rm *.bak" manually, as a typo could result in "rm * bak" instead. Do you know what that would do? #! /bin/sh # # Filename: cleanup # # Author: Br. David Carlson # # Date: September 15, 1998 # # This script does a forced removal of typical backup files in # the current directory. # rm -f *.bak rm -f .*.bak The following is another short script, but this time with a more complicated Linux command. The vertical bar is the pipe symbol. It means that the output of the echo command (in this case the value of the PATH environment variable) is piped as input into the tr command. The tr command is here used to translate any : characters into newline characters. #! /bin/sh # # Filename: showpath # # Author: Br. David Carlson # # Date: September 15, 1998 # # This script displays your path, with one directory per line. # echo $PATH | tr ':' '\n' 1) Choice constructs: The syntax for an IF..THEN..ELSE is as follows: if ... then ... else ... fi An example is the script called param, which is shown below: #! /bin/sh # # Filename: param # # Programmer: Br. David Carlson # # Date: April 21, 1994 # # This Bourne shell program simply tells you if you gave one # command-line parameter or not. # if [ $# -eq 1 ] then echo One parameter else echo Not one parameter fi Note the use of the square brackets for a test of a condition. In this case we are testing if the number of parameters (given by $# in the Bourne shell) is equal to 1. Another example is private, which is shown below: #! /bin/sh # # Filename: private # # Programmer: Br. David Carlson # # Date: March 26, 1994 # # This Bourne shell program makes a "private" file out of the # file given as the command line parameter. Read, write, and # execute permission are removed for everyone but the owner of # the file. # if [ $# -eq 1 ] # There should be 1 parameter then chmod g-rwx,o-rwx "$1" # Remove permissions for group, other else echo "One parameter needed, the name of the file to modify" fi Note that the Bourne shell uses $1 for the value of command line parameter 1, $2 for the value of command line parameter 2, etc. Other examples include public.bs, makex.bs, and removex.bs. The next example illustrates IF statements and also shows how to use test -z to check if a string is empty. #! /bin/sh # # Filename: vartest # # Programmer: Br. David Carlson # # Date: January 22, 1995 # # Illustrates use of test -z to see if a string variable is # empty. # myvar=hello if test -z "$myvar" then echo empty else echo nonempty fi # Now try again with the empty string: myvar= if test -z "$myvar" then echo empty else echo nonempty fi The general form of an extended IF is as follows: if ... then ... elif ... then ... else ... fi Here is a script for emailing me a specific file. It uses an extended IF, a test -r to see if a file can be read, and mail. #! /bin/sh # # Filename: senddc # # Programmer: Br. David Carlson # # Date: March 26, 1994 # # This Bourne shell program sends to carlsond the file given as # the command line parameter. # if [ $# -ne 1 ] then echo "One parameter needed, namely the file to send" elif test -r "$1" # test if we can read this file then echo Sending "$1" to Br. David Carlson cat "$1" | mail carlsond@acad1 else echo "Cannot read file" "$1" fi Another example is the cformat script shown below. It only runs on acad1, not on Linux, mainly because the cb program is located on acad1. #! /bin/sh # # Filename: cformat # # Programmer: Br. David Carlson # # Date: January 22, 1994 # # Description: Bourne Shell script to format the c program given # as a command line parameter. Saves a backup of the original # file. # # Example of usage: cformat test.c # if [ $# != 1 ] then echo "ERROR -- usage is: cformat filename.c" exit 1 elif [ ! -w "$1" ] then echo "ERROR -- file $1 is not writable (or does not exist)" exit 1 else cp "$1" "$1.$$" cb "$1" | tabclear > "$1.t$$" rm "$1" mv "$1.t$$" "$1" fi Besides illustrating an extended IF, this program shows a number of other things. Note that $# gives the number of command-line parameters. The very first test shows how to test if two integers are not equal. The second test shows how to check that you do NOT (exclamation point is not) have write access to the file given by the first command line parameter. Note that $$ can be used to generate a new integer, used here in naming a temporary file, just as with the C shell. The cb program used in the script is a "C beautifier" provided with the system. 2) Loop constructs: A while loop can be written as follows: while ... do ... done One example is the fix Bourne shell program which follows: #! /bin/sh # # Filename: fix # # Programmer: Br. David Carlson # # Date: April 21, 1994 # # This Bourne shell program makes all subdirectories of the # current one to be private. # set * #put filenames in parameters while test $# -ge 1 #number of parameters >= 1 do if test -d $1 #check if first parameter is a directory then echo "Making directory $1 private" chmod 700 "$1" #only let owner access this directory fi shift done Note that the condition in the while loop testing to see if the number of parameters is greater or equal to 1 could also be written using square brackets instead of test: while [ $# -ge 1 ] You also see an unusual use of the set command. The first command in this program puts all filenames in the current directory into the program's command-line parameters, 1, 2, 3, etc! Usually the set command is used to display the values of your shell variables. This is done by entering the command: set You can also use it to place a value into a variable at the command prompt: set junk=hello The above example places the string hello into a shell variable named junk. You can see this by giving the set command with no parameters or by using: echo $junk Within a shell script you do not need to use set to place a value into a shell variable. Here you could just use: junk=hello The shift command, also available in the C shell, is used to shift the command line parameters down by 1. This means that the value currently in parameter 1 is thrown away, the value in parameter 2 is placed in parameter 1, the value in parameter 3 is put into parameter 2, etc. Here it is an easy way to place the value to be checked into parameter 1 each time. A for loop looks like the following: #! /bin/sh # # Filename: count # # This Bourne shell script outputs the values 1, 2, and 3. # for k in 1 2 3 do echo $k done The following is a script available on the Linux machine for fixing the permissions on all of the files in your public_html directory. It changes the permissions to 644 so that everyone has read access to them. It does not change permissions on subdirectories or files withing subdirectories. Since the script is in the directory /usr/local/bin, which should be in your path, it can be run just by entering the publish command, without any path preceding it. #! /bin/sh # # Filename: publish # # Author: Br. David Carlson # # Date: August 10, 1998 # # This script makes the user's files in public_html to have # permissions 644 so that they are viewable by browser. USER=`whoami` PUB_DIR=/users/$USER/public_html TMP=/tmp/publish.$$ ls $PUB_DIR > $TMP sync sleep 1 while read fname do if [ -f "$PUB_DIR/$fname" ] then chmod 644 "$PUB_DIR/$fname" fi done < $TMP rm $TMP exit 0 3) Debugging options If you use the -n option on the first line of your script (as shown below), then the shell is parsed and errors are reported, but the commands in the shell script are not executed. #! /bin/sh -n If you wish to see each command of your script shown on the screen before it is executed, you can use the -x option as follows. Note that it will perform parameter and variable substitution before displaying each command. That is, a variable like $PATH will be replaced with its value and then the command containing it will be shown on the screen. #! /bin/sh -x The -v option is similar to -x in that it displays commands before they are executed. However, it does not do variable and parameter substitutions before displaying the commands. As an exercise, you might try each of these option with the count script shown earlier in this file. Further information on the Bourne shell can be found in many Unix books.