ZMSH(1zm) ZMSH(1zm) NAME zmsh - zmailer shell SYNOPSIS zmsh [-CIJLOPRSYisaefhntuvx] [-c command] [script ...] DESCRIPTION The zmsh(1zm) is an implementation of the Bourne shell suitable for use with the ZMailer router(8zm) as its configuration file language inter- preter. It contains extensions that allow structured data (in the form of lists) to be manipulated. The shell supports three basic kinds of functions: Unix commands, user- defined functions, and builtin commands. The later comes in two varia- tions: normal functions which take string arguments and return a status code (much as an embedded Unix command would work), and list-manipula- tion functions which understand list arguments and can return list arguments. The defined functions can take any form of argument and return any form of value (a status code, a string, or a list). Shell operations (pipes, backquote evaluation and substitution) will work between combinations of builtin functions, defined functions, and Unix commands. The shell precompiles its input to a (possibly optimized) byte-code form, which is then interpreted as required. This means that the orig- inal form of the input is not kept around in-core for future reference. If the input is an included file, the shell will try to save the byte- code form in a .fc file associated with the input file. For example, if input is from file.cf, the shell will try to create fc/file.fc and then file.fc. These files will in turn be searched for and loaded (after a consistency check) whenever a .cf file is included. The effects of input and output redirections are predicted prior to the execution of a command and its I/O setup. INCOMPATIBILITIES zmsh is based on the System V release 3 shell as described in a SunOS 4.0 manual page. It conforms to the behaviour of that shell, with the following differences: ^ is not accepted as an alternative pipe character. A symbol may have both a function definition and a value. The shell is 8 bit transparent. All occurrences in the sh(1) manual page of "if any character in the word is quoted" should be read as "if the word or the first character of it is quoted". The -k option is not supported. Inside backquotes, for efficient deadlock avoidance, Unix com- mands are executed in parallel. If you need serial execution, use `(c1 ; c2)` instead of `c1 ; c2`. Builtin commands that want to write more than one pipe buffer full should detach themselves into a grandchild and run to com- pletion independently. The hash builtin is not fully supported. The fancy printing options are not implemented, but program locations are hashed. If PS1 or PS2 are defined functions, then their function defini- tion will be assumed to print an appropriate prompt and the function will be called instead of printing out the value of the PS1/PS2 shell variables. In IFS, newline is always ignored (it is always a separator) when reading commands. This seems to match normal shell behaviour but not obviously so from the manual page. The SHELL environment variable is not special, since there is no restricted mode. SIGSEGV is not special. The message printed for ${FOO?...} starts with progname: instead of FOO:. The functions login, newgrp, pwd, and readonly, are not built in. Functions can have a comma-separated list of named parameters. If the argument list is exhausted on a function call, the remainder of the parameters are set to the empty string. If the parameter list is exhausted, the @ variable is set to the remainder of the arguments. This behaviour is backward compati- ble with normal shell functions. The local builtin statement declares local variables within a function scope. Builtin commands in pipelines are run within the shell, so vari- able settings in that context will affect the shell process. The type function does not print a shell function definition in text form. There is a builtin function to force its arguments to be evalu- ated as builtin function call. The termination string in here documents must be static. Some- thing like cat << `echo EOF` will not work. EXTENSIONS The following additions and extensions have been made relative to the base shell: The Korn shell backquote mechanism is supported. This means that `foo bar` is equivalent to $(foo bar) in all contexts, although the later form is preferred for clarity. If you are used to an old Bourne shell, the following are the unusual builtin functions in this shell: test (or [), getopts, times, type, builtin, sleep. The type and builtin functions are lifted from the Ninth Edition Bourne shell. The test and sleep functions are in the shell because the mailer will use them very frequently. The ssift/tsift statements are special-purpose constructs for the mailer. They act like a case statement, except the labels are regular expressions, are separated from the label body by whitespace instead of being terminated by a closing parenthesis, and exiting a ssift/tsift label body will just cause a fall-through to the next ssift / tsift label. This is similar to the production-rule semantics of Sendmail. The tsift structure has (for compability reasons) alias: sift. The difference in between ssift and tsift(sift) is on what is being matched: The tsift matches TOKENS in RFC-822 sense, while ssift at first expands the token sequence into a string, and then does the reg- expr matching. The local statement can appear anywhere in a scope (a {...} grouping) and declares variables that are created in the current scope and destroyed on exit from it. Such variables are initialized to refer to a null string. Functions may be defined with named parameters, which are scoped vari- ables and destroyed on return from the function. LIST SEMANTICS The semantics of lists have been defined in various contexts: List: (a b (c (d e) f (g))) A list may contain strings and other lists as elements. It is printed and usually entered using traditional Lisp syntax. Variable assignment: recipient=(what ever) nil=() A shell variable value may be either a string or a list. A list value can be entered directly. Element counts: $#variable $(length $(expression)) Every list-valued variable has a length accessed using the $# prefix, as in csh (1) syntax. The length builtin function can also be used to count the number of toplevel elements of a list. Empty lists have length 0. Strings have no length. Command line: router $(list smtp neat.cs rayan) (...) Command-line arguments to builtin or defined functions may be lists. The first argument cannot be entered directly as a list, but later arguments may be. The restriction is due to a syntax clash with function definitions. Loops: for i in yes (a b c) no; do; ...; done A list in a loop list is treated as a single element. The loop variable will be bound to it. Associative (property) lists: $(get variable symbol) The value of variable should be a list of even length, with alternating attributes and values. The given symbol is matched with an attribute, and the following value is returned. Associative (property) assignment: setf $(get variable symbol) value The setf function is used to change the value that would be returned by an expression, typically this is done by pointer manipulation. Some new builtin functions have been defined to operate on lists: car (or first), returns the first element of the list which is its argument. cdr (or rest), returns the list after the first element of the list which is its argument. elements is used to explode a list, for use in a loop or to concatenate the list elements together. For example: hostlist=(neat.cs smoke.cs) for hosts in $(elements hostlist) do ... done get is a property list lookup function. Property lists are lists of alternating keywords (properties or attributes) and values. For example: jane=(hair brown eyes blue) get $jane eyes grind is used for lists instead of echo, use it to print a list value. last returns the last element of the list which is its argument. length returns the count of elements of the list which is its argument. list returns the list containing its arguments as elements. setf takes a retrieval command and a new value as arguments. At present it works with (combinations of) car, cdr, get and last. For example: setf $(get $jane eyes) azur Lists are ignored in any context where they aren't expected. For exam- ple, a list value as an argument to echo would behave just like a null argument. Builtin functions either know about lists (which subsumes normal strings), or about string values. Defined functions are flexi- ble, whatever you pass them will show up in their argument list. On a command line, the first argument can never be written as a list (since the parser won't be able to tell that from a function defini- tion). However, the following arguments may be written as lists. This leads to constructs like: aliasexpand $(list local - rayan) plist The one exception to this is in the return statement, which may be given a list (or string) as its argument. If so, the return value from the defined function becomes list-valued, and the status code is set to 0. If the argument to the return statement is numeric, it is assumed to be the desired status code. Be forewarned of strange effects if you print to stdout in a list-val- ued function that is called within a backquote (i.e. where the return value, not the status, is desired) and you expect a list back. OPTIONS The following debugging options are specific to the internal function of zmsh: -C print code generation output onto stdout. If this option is doubled, the non-optimized code is printed out instead. -I print runtime interpreter activity onto /dev/tty; argv:s of exe- cutes, assignments, variables, ... -J print runtime interpreter activity onto /dev/tty; just argv:s of executes. -L print lexer output onto stdout. -O optimize the compiled script. If this option is doubled, the optimized code is also printed out. -P print parser output (S/SL trace output) onto stdout. -R print I/O actions onto /dev/tty. -S print scanner output (token assembly) onto stdout. -Y open /dev/tty for internal debugging use. These are the normal shell options that are supported by zmsh: -c run the given argument as a shell command script. -i this shell is interactive, meaning prompts are printed when ready for more input, SIGTERM is ignored, and the shell doesn't exit easily. This flag is automatically set if stdin and stderr are both attached to a tty. -s read commands from stdin. If there are non-option arguments to the shell, the first of these will be interpreted as a shell script to open on stdin, and the rest as arguments to the script. -a automatically export new or changed shell variables. -e exit on non-zero status return of any command. -f disables filename generation (a.k.a. "globbing"). -h hash and cache the location of Unix commands. This option is set by default. -n read commands but do not execute them. -t exit after running one command. -u unset variables produce an error on substitution. -v print shell input as it is read. -x print commands as they are executed. BUGS Nested here documents don't work with optimization off, and terminator string isn't stacked. Hitting interrupt during I/O stuff is a bad thing. The file descriptor prediction doesn't always work, especially in (nested) multi-pipe command lines. SEE ALSO sh(1), router(8zm), zmailer.conf(1zm). AUTHOR This program authored and copyright by: Rayan Zachariassen <no address> Some "small" tweaks by: Matti Aarnio <mea@nic.funet.fi> 2003-Aug-28 ZMSH(1zm)