Originally Published: Friday, 29 September 2000 Author:
Published to: develop_articles_tutorials/Development Tutorials Page: 1/1 - [Std View]

Shell Scripting

The Unix shell is able to do much more than invoke simple commands. Great many tasks can be performed by writing a short shell script, so knowing the shell language is a fundamental skill of a Unix user.

The Unix shell, or the command shell, is the program that shows you the shell prompt and accepts commands such as ls /usr/bin. Compared to command shells on most other systems, the unix shell is a very complex program: a command like ls /usr/bin/ is in fact a statement in the shell language, using which it's possible to build quite complex programs.

There are two primary dialects of shell languages: the Bourne shell (sh) and the C shell (csh). The Bourne shell was the original Unix shell, and as such is the simplest one the of general purpose Unix shells. Backwards compatible with sh are the GNU Bourne-Again shell (bash), the Korn shell (ksh), the Z shell (zsh) and some others. The program in /bin/sh is expected to execute the Bourne shell language. Bash is the standard shell in many Linux distributions. The C shell is so named because its syntax looks more like C than does syntax of sh. Backwards compatible with csh is its enhanced version tcsh (the letter t is obviously an arbitrary choice).

An Example Program

You can put the shell language statements into a file that starts with #!/bin/sh, and then execute that file like any other command. Below is a Bourne shell script, or a Bourne shell program if you wish, that tells a user some information about his system:


echo "You're running `uname -s` version `uname -r`"
for x in ash bash bsh csh ksh pdksh sh tcsh zsh; do
	test -x /bin/$x && shells="$shells $x"
echo "You have at least the following shells installed:$shells"

You run that program by pasting it into a file, let's say sysinfo.sh, giving the file execute permissions with chmod +x sysinfo.sh, and then executing it by issuing command ./sysinfo.sh.

The first line #!/bin/sh tells the operating system to execute the specified command /bin/sh with the filename as the first argument. That is, if you run the program as instructed above, the operating system runs a command /bin/sh ./sysinfo.sh. Since the dash (#) starts a comment in shell (and indeed in any language that can be run using this mechanism), the first line will be ignored in the actual execution of the program.

The first echo line outputs something like "You're running Linux version 2.2.16". A command between backticks (` - not to be confused with the single quote character ') is executed as a shell command, whose output then replaces the backticks and the command. That is, `uname -s` is replaced by the output of command uname -s, which on my system is "Linux".

The second line starts a for loop that ends to the done statement. It sets variable x to each element of the list ash bash ... zsh in turn, and executes the indented line each time. The indented line tests if file /bin/$x (during the first iteration, /bin/ash) exists and is executable, and if so, appends the current value of x to a variable shells. The keyword && indicates that the command following it is only executed if the command preceding it returns a true value.

The last line of the program should be obvious. On my system it outputs "You have at least the following shells installed: bash csh ksh sh tcsh zsh".

What the Shell Language Is and Isn't Good For

The shell language is good for automating the sort of tasks one typically performs in shell: file manipulation and invocation of utility programs. Installation script is a good example of the kind of programs traditionally written in the shell language. They don't need to be fast, they manipulate files a lot, they are quite short, and they usually need to be very portable. If the installation is more complex, it's still common to use a shell script, but invoke programs written in different languages from it.

The portability of shell scripts is debatable. While all Unixes have Bourne shell, it may be very hard to write real world portable shell scripts. Doing that requires very thorough knowledge about what features of the Bourne shell are truly portable. It's necessary to also know which helper utilities exist in all Unixes, and which features are the same in all of them, because shell scripts rely heavily on utility programs.

The Real Power of Shell: Combining Small Programs

This text has discussed the shell language like one could discuss any other language. However the real significance of the shell lies in its ability to combine programs conveniently using pipes, command substitution, redirection etc. These mechanisms are one of the fundamental things that make Unix what it is, and must be understood to make effective use of the shell, and by large Unix itself. Making these scripts possible is why Unix commands typically output nothing unnecessary and why files contain simple ASCII instead of binary data whenever possible.

This approach works best with short programs, often "one liners" entered directly on the shell prompt, which are able to make heavy use of existing utilities with only little glue in between. Amazingly often it's possible to get the job done with a script just like that, and that's why every Unix user should feel at home with the shell language.

Links For More Information