Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Posting-Version: version B 2.10.1 6/24/83; site alice.UUCP Path: utzoo!watmath!clyde!burl!ulysses!allegra!alice!rob From: rob@alice.UucP (Rob Pike) Newsgroups: net.unix Subject: Shells, features and interaction Message-ID: <4575@alice.UUCP> Date: Sun, 17-Nov-85 14:44:22 EST Article-I.D.: alice.4575 Posted: Sun Nov 17 14:44:22 1985 Date-Received: Mon, 18-Nov-85 07:42:02 EST Organization: Bell Labs, Murray Hill Lines: 99 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