Shells, features and interaction

Rob Pike rob at alice.UucP
Mon Nov 18 05:44:22 AEST 1985


The recent shell discussion prompted by Arnold Robbins's announcement has
missed an important point: effective programmability in an interactive
system can obviate many supposed `features'.

Those who claim shell functions are the way to do aliasing are right, but
the only implementation that works properly for this purpose is in the
8th edition shell.  The problem is that unless functions can be exported,
they are unavailable to subshells and shell files.  In the 8th edition shell,
functions are literally exported, and passed in the environment as
shell input text.  This sounds expensive, but on most current systems,
argument and environment passing through exec(2) is so efficient that a few
Kbytes of extra environment are probably cheaper than adding a directory
to PATH.  Shells like csh or ksh that read function (or equivalent) definitions
from a file at start up have peculiar semantics, can't provide an export
facility that works properly, and are probably no more efficient.

Functions can be used for much more than providing aliases.  For the
novitiate:
	f(){
		cmd
	}
is the shell syntax for functions.  'cmd' is any text, however many lines
you'd like, exactly as it would appear in a shell file.  The only difference
is that you 'return' from a function instead of 'exit.'  After f is defined,
it is invoked as any command, and 'cmd' may refer to the function arguments
as $1, $2, $#, etc.  So aliases are obviously trivial.  Now some v8isms:
	builtin cmd ...
runs cmd directly, but looks cmd up in the list of builtin functions first.
This allows functions to be evaluated first and override builtin functions:
	cd(){
		echo my cd
		builtin cd $1
	}
Function names may be anything printable, but may not contain = or ( to
simplify parsing.  Thus:
	ls-l(){
		ls -l $*
	}
and so on.

Because functions are evaluated locally, you can use them to do things
impossible in shell files.  For example, if the shell writes its input
text to a file with a known name, say $HISTORY, you can invest an arbitrary
amount of effort in the history manipulating program, but have it merely
print the resulting command.  A function can then collect the output
and eval it, so history works for any command even though the code for
supporting it is outside the shell.

People want to build things in to the shell for efficiency,
but every builtin is one less thing you can change (although functions clearly
mitigate this somewhat).  test is often built in to avoid the costly fork and
exec.  But most tests are doing string comparisons, and in fact the shell
semantics for string comparison is rather more powerful but has a peculiar
syntax.  What people say is:
	if test "$1" = "$2"
	then cmd
	fi
which is easy to read, but slow.  So they build in test.  More efficient
is the case statement:
	case "$1" in
	"$2") cmd
	esac
But it's weird.  Functions to the rescue:
	equal(){
		case "$1" in
		"$2") return 0 ;;
		*) return 1
		esac
	}
	if equal "$1" "$2"
	then ....

Obviously what's needed is a function library, as in any programming language.

Similar thought applied to things like expr(1) can show why expr needn't be
built in - when expr is in the inner loop it's usually doing something simple
like incrementing a variable.  Why not provide a looping primitive, and rewrite
the loop as something like:
	for i in `loop 1 100`
	do foo $i
	done
?

The next time someone hands you a shell with nice interactive features
or builtin commands, ask whether the implementer understands where the
power of the shell should lie.  The Bourne shell is the favorite for
shell commands, the csh for interaction.  But by addressing interaction
as a programmability problem, the interactive and programming shells
can be the same without sacrificing grace in either environment.

One final note:

text	data	bss	dec	hex
27648	1024	2568	31240	7a08	/bin/sh		8th edition shell
67584	2048	5740	75372	1266c	/bin/csh	C shell
81920	3072	9224	94216	17008	/usr/lbin/ksh	Korn shell


					Rob Pike



More information about the Comp.unix mailing list