Вы находитесь на странице: 1из 7

Shell Script Programming Guidelines

This document details some guidelines that should be followed when developing UnixShell Program code. Lawson Hanson
Bureau of Meteorology Research Centre

December 2, 2005

Which Shell?

Several command line interpreters (shells) including the Bourne Shell, C-Shell, and Korn Shell are available on most Unix systems. Although the C-Shell and Korn Shell have some very useful features which help to make your interactive use of those shells more productive, in general, unless you can substantiate valid reasons for doing otherwise, the Bourne Shell should be used as the standard shell for writing shell programs. The main reasons for this are that the Bourne Shell is: Available on all Unix platforms Compared to the C-Shell, it promotes a modular coding style because it provides the user with the ability to dene their own functions Input/output redirection is more manageable in the Bourne Shell making it easy to capture separate STDOUT and STDERR streams, or to combine them into one, if required For some more of the reasons why the C-Shell should not be used for writing shell scripts of any great complexity, you may nd it informative to read the following article: Csh Programming Considered Harmful , by Tom Christiansen, which can be easily located on the web. You can specically nominate the shell the system will use to run a shell script program by including the following, so called hash-bang line, as the rst line of your programs: #!/bin/sh

Features of the Bourne Shell

In the words of Steve Bourne, the author of the Bourne Shell1 , the following notes describe some important features of the shell, and the following sub-section describes the operation of the shell as it interprets and executes the commands contained in your Bourne Shell scripts. The shell is a command programming language that provides an interface to the UNIX operating system. Its features include control-ow primitives, parameter passing, variables and string substitution. Constructs such as while, if-then-else, case and for are available. Two-way communication is possible between the shell and commands. String-valued parameters, typically le names or ags, may be passed to a command.
UNIX 1 Bourne,

is a registered trademark of The Open Group. S.R., The UNIX System, Addison-Wesley, 1983.

A return code is set by commands that may be used to determine control-ow, and the standard output from a command may be used as shell input. The shell can modify the environment in which commands run. Input and output can be redirected to les, and processes that communicate through pipes can be invoked. Commands are found by searching directories in the le system in a sequence that can be dened by the user. Commands can be read either from the terminal or from a le, which allows command procedures to be stored for later use.


Evaluation and Quoting

The shell is a macro processor that provides parameter substitution, command substitution and le name generation for the arguments to commands. Before a command is executed the following substitutions occur: parameter substitution, e.g. $user command substitution, e.g. pwd Only one evaluation occurs so that if, for example, the value of the variable X is the string $y then echo $X will echo $y. blank interpretation Following the above substitutions the resulting characters are broken into non-blank words (blank interpretation). For this purpose blanks are the characters of the string $IFS. By default, this string consists of blank, tab and newline. The null string is not regarded as a word unless it is quoted. For example, echo will pass on the null string as the rst argument to echo, whereas: echo $null will call echo with no arguments if the variable null is not set or set to the null string. le name generation Each word is then scanned for the le pattern characters *, ? and [...] and an alphabetical list of le names is generated to replace the word. Each such le name is a separate argument. The evaluations just described also occur in the list of words associated with a for loop. Only substitution occurs in the word used for a case branch.

Indentation, Blank Lines and Statement Form

Indentation should be used to improve the readability of your shell programs. The unit of indentation should be a consistent four (4) spaces. Blank lines should be used to help improve readability. It is preferable to place the various components of compound statements on separate lines. This will help to make your programs more readable by humans. Instead of writing your shell scripts (or any other program, for that matter) in the most compact form that you can, such as that shown in the following example:

#!/bin/sh if [ ! -f file.dat ] ; then echo "file.dat: File not found." exit 1 fi It is far more preferable to write: #!/bin/sh # if [ ! -f file.dat ] then echo "file.dat: File not found." exit 1 fi exit 0 Note: Please do not use Tab characters for indentation; spaces simplify neat, consistent printing. If you use the vi editor, then you can dene a macro to help with indentation, and for example: :map g 0i ^V^[

will make use of the (generally unused command) g key to make it insert four spaces at the left-hand side of the current line. The ^V and ^[ character pairs represent a Control-V followed by the Esc key, which will reduce to just the ^[ as you type it, and so maps the g key to enable it to carry out the implied vi commands: 0 i ^[ move insert point to before the left-most character on the current line commence insert mode insert four spaces exit insert mode, i.e., return to command mode

And of course, such a macro can be added (i.e., without the leading colon : character) to your .exrc le so that it will be available in every vi session.

Line Length

The length of lines should be kept to no more than 80 characters. Although shell script programs ultimately get read and interpreted by the shell, an important part of anything requiring more than just a few lines of code is your eorts to make the code as humanly readable as possible. Many humans nd a line of text with about sixty (60) characters to be relatively comfortable to read . . . however, documents containing extremely long lines become very tedious to read. Most long commands can be broken at convenient places by using a backslash (\) character as the last character on the end of a line to signify that the command continues on the next line. gfind /data -type f -a \( -name core \) \ -o \( -name *.mon -mtime +30 \) \ -o \( -name *.fgb -size +13312k \) -ls


Environment Variables

Unix Environment Variables should be declared with identier names in ALL UPPER CASE characters. The underscore character (_) may sometimes be used to increase readability.

PATH="/bin:/usr/bin:/${HOME}/bin:." PRINTER=nhp11; export PRINTER F90_SITE_OPTIONS=-ew; export F90_SITE_OPTIONS


Other Shell Variables

Variables should be declared with name identiers that help to disclose their intended scope. Global (to the current shell and any dened functions) variables should be declared with the rst character of each word in Upper Case; local variables should have lower case name identiers. In the following example, InputFile is a global variable (because it is set outside, but used inside the function fnListData; by contrast, the variable reply is considered to be a local variable. The Bourne shell does not really contain dierent global and local scoping for variables, but it helps to name variables in this way to provide some indication of the purpose for each variable. InputFile="${HOME}/lib/project.data" fnListData ( ) { if [ -f $InputFile ] then more $InputFile fi } /bin/echo -n "List the data file? [Y/N]: " read reply case $reply in [Yy]*) fnListData ;; *) ;; esac

Shell Functions

Functions can be declared anywhere in the shell program before the function is rst referenced. The preferred method is to declare shell functions at the beginning of the program le, and have the main body of the program towards the end of the le. A shell function is declared and used as follows: name ( ) { command; ... command; } Although the spaces between the parentheses are not necessary, it is necessary to have at least one whitespace character between the left-curly-brace and the rst command of the function body, and a semicolon must separate the last command in the function body from the closing right-curly-brace if they are on the same line. Prog=basename $0 .sh fnUsage ( ) { echo echo "Usage: ${Prog} arg1 arg2 arg3" echo } if [ $# -lt 3 ]

then fnUsage exit 1 fi


Function Names

The naming of Shell Functions should follow similar conventions to those outlined above for Shell Variables, however, it is preferable to prex the name with the characters fn, so there will be no confusion as to whether it is a variable name, or (as is implied by the fn prex) that of a function. fnGetYesOrNo ( ) { while [ 1 -ne 0 ] # i.e.: forever do /bin/echo -n "$* ? [Y/N]: " read YorN case ${YorN} in Y*|y*) YorN=y break ;; N*|n*) YorN=n break ;; *) continue ;; esac done } fnGetYesOrNo "Do you want hard copy" [ "x${YorN}" = "xy" ] && a2ps -2 hard-copy Note: Arguments passed to shell functions are available as positional parameters $1, $2, $3, etc., inside the shell function code. Hence, the call to fnGetYesOrNo "Do you want hard copy" above will pass one argument "Do you want hard copy" to the function, and it is used inside the function as: echo -n "$* ? [Y/N]: ", where the $* item means: all arguments, or all positional parameters. Note Also: The positional parameters of the main program will be overwritten when a call is made to a shell function, so if these are important, they should rst be saved: args="$*" fnGetYesOrNo "Do you want hard copy" set $args date=$1 time=$2 ... ... ... Shell functions may be declared in a separate le (especially where they are of a global nature, and will be used by other programs), and can be sourced by (i.e.: read into) the current shell program by using the . (dot) command:

. ${HOME}/lib/shell-funcs.sh


Return Values

By default, shell functions will return a value of zero (0) on success, or a non-zero value on failure; however, the user may specify a particular return value by using the return statement: return 55 Note: Return values can only be very small (0 through 255) integers

Exit Values

By default, Unix uses an exit status code of zero (0) to mean success, and hence a non-zero exit status code will mean failure; however, the user may (and indeed is encouraged to) specify a unique exit value for each dierent exit reason, by using the exit statement: if [ $# -lt 2 ] then echo "${Prog}: Not enough arguments" exit 7 fi Note: Exit values can only be very small (0 through 255) integers

The reader may nd the following list of books and other reference material useful in the pursuit of Unix shell programming: Aho, A.V., Kernighan, B.W., and Weinberger, P.J., The AWK Programming Language, 210 pages, Addison-Wesley, 1988. Written by the developers of the AWK language, this book contains excellent examples of how to use AWK to great eect. Anderson, G., and Anderson, P., The UNIX C Shell Field Guide, 374 pages, Prentice-Hall, 1986. Users of the C Shell will nd this an excellent source of information. Bolsky, M.I., and Korn, D.G., The Kornshell Command and Programming Language, 356 pages, Prentice-Hall, 1989. Co-authored by David Korn (developer of the Korn shell), this book contains a very thorough description of the many features of this popular shell. Bourne, S.R., The UNIX System, 351 pages, Addison-Wesley, 1983. Written by the author of the Bourne Shell, covers a wide range of Unix topics. Kernighan, B.W., and Pike, R., The UNIX Programming Environment, 357 pages, Prentice-Hall, 1984. Getting a bit old now, but still contains much useful information. Kochan, S.G., and Wood, P.H., UNIX Shell Programming, 490 pages, Hayden Books, 1990. Concentrates solely on shell programming, and makes mention of the Korn shell, too. Manis, R., and Meyer, M.H., The UNIX Shell Programming Language, 303 pages, Howard Sams, 1986. Newham, C., and Rosenblatt, W., Learning the bash Shell , 292 pages, OReilly and Associates, 1995.

Peek, J., Loukides, M., et. al., UNIX Power Tools, 1162 pages plus a CD, OReilly and Associates, 1993. Covers shell scripting as well as providing examples of many other tools and utilities that can be used together to create powerful solutions to common problems. Rosenblat, W., Learning the Korn Shell , 363 pages, OReilly and Associates, 1993. Introductory but thorough coverage of the Korn shell. Oh, and dont forget to browse through the Unix man pages; these will always provide the denitive answer about the operation of the features of the various shells and other software tools. See: man man, man sh, man csh, man ksh, etc.