byron@archone.tamu.edu (Byron Rakitzis) (05/22/91)
Submitted-by: Byron Rakitzis <byron@archone.tamu.edu> Posting-number: Volume 20, Issue 10 Archive-name: rc/part01 rc is a command interpreter and programming language similar to sh(1). It is based on the AT&T plan 9 shell of the same name. The shell offers a C-like syntax (much more so than the C shell), and a powerful mechanism for manipulating variables. It is reasonably small and reasonably fast, especially when compared to contemporary shells. Its use is intended to be interactive, but the language lends itself well to scripts. This shell was written by me, Byron Rakitzis, but kudos go to Paul Haahr for letting me know what a shell should do and for contributing certain bits and pieces to rc (notably the limits code, most of which.c and the backquote redirection code), and to Hugh Redelmeier for running rc through his fussy ANSI compiler and thereby provoking interesting discussions about portability, and also for providing many valuable suggestions for improving rc's code in general. Finally, many thanks go to David Sanderson, for reworking the man page to format well with troff, and for providing many suggestions both for rc and its man page. Of course, without Tom Duff's design of the original rc, I could not have written this shell (though I probably would have written *a* shell). Almost of all of the features, with minor exceptions, have been implemented as described in the Unix v10 manuals. Hats off to td for designing a C-like, minimal but very useful shell. Byron Rakitzis -------------- #! /bin/sh # This is a shell archive. Remove anything before this line, then feed it # into a shell via "sh file" or similar. To overwrite existing files, # type "sh file -c". # The tool that generated this appeared in the comp.sources.unix newsgroup; # send mail to comp-sources-unix@uunet.uu.net if you want that tool. # Contents: README builtins.c hash.h rc.1 # Wrapped by kent@sparky on Wed May 22 01:21:49 1991 PATH=/bin:/usr/bin:/usr/ucb ; export PATH echo If this archive is complete, you will see the following message: echo ' "shar: End of archive 1 (of 4)."' if test -f 'README' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'README'\" else echo shar: Extracting \"'README'\" \(3564 characters\) sed "s/^X//" >'README' <<'END_OF_FILE' XThis is release 1.0 of rc. X XRead COPYRIGHT for copying information. All files are X XCopyright 1991, Byron Rakitzis. X X------ Compiling rc: X XTo compile rc, you need an ANSI compiler like gcc. Some compilers which Xgrok prototypes can also compile rc. In particular, I have successfully Xcompiled rc using "cc" on the sgi running IRIX-3.3.1 (version 3.2 has Xan older compiler---rc won't compile under that OS). I avoid using Xstandard header files as much as possible. In most cases, this is a Xwin, but you should pay attention to stddef.h and to rc.h to make Xsure the values there are suitable for your system. X XNote: if you have an IBM PC-RT, you *can* compile rc with IBM's Xcompiler but you have to tweak the sources a little. I decided not to Xsupport the RT because /usr/include does not have a stdarg.h, but Xdesperate RT users can contact me for porting info. X XIf you are on a pure system V machine, you may have define certain Xmacros to omit certain pieces of code. In particular, defining the XNOLIMITS macro will #ifdef out the Berkeley limits code. XAlso, the NOJOB macro if defined will omit certain calls to signal() Xused to make rc work on Berkeley systems that assume csh. (note that rc Xdoes *not* support csh-style job control in either case) XSimilarly, the NONMPIPES macro omits support for <{} redirection on Xsystems which do not support named pipes. X XFinally, on older systems without "<dirent.h>", the macro X"NODIRENT" must be defined. This substitutes "<sys/dir.h>" for X"<dirent.h>" and uses struct direct instead of struct dirent. X X------ Bugs: X XSend bug reports to byron@archone.tamu.edu. If a core dump is Xgenerated, sending me a backtrace will help me out a great deal. You Xcan get a backtrace like this: X X ; gdb rc core X (gdb) where X <<<BACKTRACE INFO>>> X (gdb) X XAlso, always report the machine, compiler and os used to make rc. It's Xpossible I may have access to a machine of that type, in which case it Xbecomes much easier for me to track the bug down. X X------ Man page: XThe man page works with nroff on my Sun, but I had to use groff in Xorder to get the sample code to be typeset in typewriter type. I Xam assuming that ditroff will also format rc.1 correctly for a Xprinter. If anyone can tell me how to get BSD troff to do this, XI would be grateful. X X------ Feeping Creaturism: X XSee the end of the man page, under "INCOMPATIBILITIES" for (known?) Xdifferences from the "real" rc. Most of these changes were necessary Xto get rc to work in a reasonable fashion on a real UNIX system; a Xfew were changes motivated by concern about some inadequacies in Xthe original design. X X------ Credits: X XThis shell was written by me, Byron Rakitzis, but kudos go to Paul XHaahr for letting me know what a shell should do and for contributing Xcertain bits and pieces to rc (notably the limits code, most of which.c Xand the backquote redirection code), and to Hugh Redelmeier for running Xrc through his fussy ANSI compiler and thereby provoking interesting Xdiscussions about portability, and also for providing many valuable Xsuggestions for improving rc's code in general. Finally, many thanks Xgo to David Sanderson, for reworking the man page to format well with Xtroff, and for providing many suggestions both for rc and its man page. X XOf course, without Tom Duff's design of the original rc, I could not Xhave written this shell (though I probably would have written *a* Xshell). Almost of all of the features, with minor exceptions, have been Ximplemented as described in the Unix v10 manuals. Hats off to td for Xdesigning a C-like, minimal but very useful shell. END_OF_FILE if test 3564 -ne `wc -c <'README'`; then echo shar: \"'README'\" unpacked with wrong size! fi # end of 'README' fi if test -f 'builtins.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'builtins.c'\" else echo shar: Extracting \"'builtins.c'\" \(10271 characters\) sed "s/^X//" >'builtins.c' <<'END_OF_FILE' X/* builtins.c: the collection of rc's builtin commands */ X X#include <setjmp.h> X#ifndef NOLIMITS X#include <sys/time.h> X#include <sys/resource.h> X#endif X#include "rc.h" X#include "utils.h" X#include "walk.h" X#include "input.h" X#include "builtins.h" X#include "hash.h" X#include "nalloc.h" X#include "status.h" X#include "footobar.h" X#include "lex.h" X#include "open.h" X#include "except.h" X#include "redir.h" X#include "glom.h" X#include "tree.h" X Xextern int umask(int); X Xstatic void b_break(char **), b_builtin(char **), b_cd(char **), X b_echo(char **), b_eval(char **), b_exit(char **), b_limit(char **), X b_return(char **), b_shift(char **), b_umask(char **), b_wait(char **), X b_whatis(char **); X Xstatic builtin_t *const builtins[] = { X b_break, b_builtin, b_cd, b_echo, b_eval, b_exec, b_exit, X b_limit, b_return, b_shift, b_umask, b_wait, b_whatis, b_dot X}; X Xstatic char *const builtins_str[] = { X "break", "builtin", "cd", "echo", "eval", "exec", "exit", X "limit", "return", "shift", "umask", "wait", "whatis", "." X}; X Xbuiltin_t *isbuiltin(char *s) { X int i; X X for (i = 0; i < arraysize(builtins_str); i++) X if (streq(builtins_str[i], s)) X return builtins[i]; X return NULL; X} X X/* funcall() is the wrapper used to invoke shell functions. pushes $*, and "return" returns here. */ X Xvoid funcall(char **av) { X jmp_buf j; X Estack e1, e2; X X if (setjmp(j)) X return; X X starassign(*av, av+1, TRUE); X except(RETURN, j, &e1); X except(STAR, NULL, &e2); X walk(treecpy(fnlookup(*av),nalloc), TRUE); X varrm("*", TRUE); X unexcept(); /* STAR */ X unexcept(); /* RETURN */ X} X X/* a dummy command. not really used to exec commands (exec() does this simply by not forking) */ X Xvoid b_exec(char **av) { X if (av[1] == NULL) /* on a null exec, perform redirections */ X doredirs(); X return; X} X X/* echo -n omits a newline. echo -- -n echos '-n' */ X Xstatic void b_echo(char **av) { X SIZE_T i; X char *format = "%a\n"; X X if (*++av != NULL) { X if (streq(*av, "-n")) { X format = "%a"; X av++; X } else if (streq(*av, "--")) { X av++; X } X } X X i = strarraylen(av) + 1; /* one for the null terminator */ X X if (i < FPRINT_SIZE) X fprint(1, format, av); X else X writeall(1, sprint(nalloc(i), format, av), i-1); X set(TRUE); X} X X/* cd. traverse $cdpath if the directory given is not an absolute pathname */ X Xstatic void b_cd(char **av) { X List *s, nil; X char *path = NULL; X SIZE_T t, pathlen = 0; X X if (*++av == NULL) { X s = varlookup("home"); X *av = (s == NULL) ? "/" : s->w; X } X if (isabsolute(*av)) { /* absolute pathname? */ X if (chdir(*av) < 0) { X set(FALSE); X uerror(*av); X } else X set(TRUE); X } else { X s = varlookup("cdpath"); X if (s == NULL) { X s = &nil; X nil.w = ""; X nil.n = NULL; X } X do { X if (s != &nil && *s->w != '\0') { X t = strlen(*av) + strlen(s->w) + 2; X if (t > pathlen) X path = nalloc(pathlen = t); X strcpy(path, s->w); X strcat(path, "/"); X strcat(path, *av); X } else { X pathlen = 0; X path = *av; X } X if (chdir(path) >= 0) { X set(TRUE); X if (interactive && *s->w != '\0' && !streq(s->w,".")) X fprint(1,"%s\n",path); X return; X } X s = s->n; X } while (s != NULL); X fprint(2,"couldn't cd to %s\n", *av); X set(FALSE); X } X} X Xstatic void b_umask(char **av) { X int i; X X if (*++av == NULL) { X set(TRUE); X i = umask(0); X umask(i); X fprint(2,"0%o\n",i); X } else { X i = o2u(*av); X if ((unsigned int) i > 0777) { X set(FALSE); X fprint(2,"bad umask\n"); X } else { X set(TRUE); X umask(i); X } X } X} X Xstatic void b_exit(char **av) { X int s; X X if (av[1] == NULL) X rc_exit(getstatus()); X if ((s = a2u(av[1])) >= 0) X rc_exit(s); X fprint(2,"%s is a bad number\n", av[1]); X rc_exit(1); X} X X/* raise a "return" exception, i.e., return from a function. if an integer argument is present, set $status to it */ X Xstatic void b_return(char **av) { X int s; X X if (av[1] != NULL) { X s = a2u(av[1]); X if (s < 0) { X fprint(2,"%s is a bad number\n", av[1]); X set(FALSE); X } else { X setstatus(s << 8); X } X } X rc_raise(RETURN); X} X X/* raise a "break" exception for breaking out of for and while loops */ X Xstatic void b_break(char **av) { X rc_raise(BREAK); X} X X/* shift $* n places (default 1) */ X Xstatic void b_shift(char **av) { X int shift; X List *s, *dollarzero; X X shift = (av[1] == NULL ? 1 : a2u(av[1])); X X if (shift < 0) { X fprint(2,"%s is a bad number\n", av[1]); X set(FALSE); X return; X } X X s = varlookup("*")->n; X dollarzero = varlookup("0"); X X while(s != NULL && shift != 0) { X s = s->n; X --shift; X } X X varassign("*", append(dollarzero, s), FALSE); X set(TRUE); X} X X/* works by advancing argv by one, really. This means that if builtin is defined as a function you are hosed */ X Xstatic void b_builtin(char **av) { X builtin_t *b; X X if (av[1] == NULL) { X set(FALSE); X fprint(2,"no arguments to 'builtin'\n"); X return; X } X if ((b = isbuiltin(av[1])) == NULL) { X set(FALSE); X fprint(2,"no such builtin\n"); X } else { X set(TRUE); X b(++av); X } X} X X/* wait for a given process, or all outstanding processes */ X Xstatic void b_wait(char **av) { X int stat, pid; X X if (av[1] == NULL) { X pid = wait(&stat); X if (pid < 0) X uerror("wait"); X while(wait(&stat) >= 0) X ; X return; X } else { X pid = a2u(av[1]); X if (pid < 0) { X set(FALSE); X fprint(2,"%s is a bad number\n", av[1]); X return; X } X while (pid != wait(&stat)) X if (pid < 0) X uerror("wait"); X } X if (pid < 0) X set(FALSE); X else X setstatus(stat); X} X X/* X whatis without arguments prints all variables and functions. Otherwise, check to see if a name X is defined as a variable, function or pathname. X*/ X Xstatic void b_whatis(char **av) { X enum bool f,found; X int i,j; X List *s,*t; X Node *n; X char *e; X X if (av[1] == NULL) { X whatare_all_vars(); X set(TRUE); X return; X } X found = TRUE; X for (i = 1; av[i] != NULL; i++) { X f = FALSE; X if ((s = varlookup(av[i])) != NULL) { X f = TRUE; X fprint(1,"%s=%s", av[i], (s->n == NULL ? "" : "(")); X for (t = s; t->n != NULL; t = t->n) X fprint(1,"%s ",strprint(t->w, FALSE, TRUE)); X fprint(1,"%s%s\n",strprint(t->w, FALSE, TRUE), (s->n == NULL ? "" : ")")); X } X if ((n = fnlookup(av[i])) != NULL) { X f = TRUE; X fprint(1,"fn %s {%s}\n",av[i],ptree(n)); X } else if (isbuiltin(av[i]) != NULL) { X f = TRUE; X for (j = 0; j < arraysize(builtins_str); j++) X if (streq(av[i], builtins_str[j])) X break; X fprint(1,"builtin %s\n",builtins_str[j]); X } else if ((e = which(av[i])) != NULL) { X f = TRUE; X fprint(1,"%s\n",e); X } X if (!f) { X found = FALSE; X fprint(2,"%s not found\n", av[i]); X } X } X X set(found); X} X X/* push a string to be eval'ed onto the input stack. evaluate it */ X Xstatic void b_eval(char **av) { X boolean i = interactive; X X if (av[1] == NULL) X return; X X interactive = FALSE; X pushinput(STRING, av + 1); X doit(TRUE); X interactive = i; X} X X/* X push a file to be interpreted onto the input stack. with "-i" treat this as an interactive X input source. X*/ X Xvoid b_dot(char **av) { X int fd; X boolean old_i = interactive, i = FALSE; X Estack e; X X av++; X X if (*av == NULL || **av == '\0') X return; X X if (streq(*av,"-i")) { X av++; X i = TRUE; X } X X if (dasheye) { /* rc -i file has to do the right thing. reset the dasheye state to FALSE, though. */ X dasheye = FALSE; X i = TRUE; X } X X fd = rc_open(*av, FROM); X X if (fd < 0) { X if (rcrc) /* on rc -l, don't flag nonexistence of .rcrc */ X rcrc = FALSE; X else X uerror(*av); X set(FALSE); X return; X } X rcrc = FALSE; X X starassign(*av, av+1, TRUE); X pushinput(FD, fd); X interactive = i; X except(STAR, NULL, &e); X doit(TRUE); X varrm("*", TRUE); X unexcept(); /* STAR */ X interactive = old_i; X} X X/* Berkeley limit support was cleaned up by Paul Haahr. */ X X#ifdef NOLIMITS Xstatic void b_limit(char **av) { X fprint(2,"rc was compiled without berkeley limits\n"); X set(FALSE); X} X#else X Xtypedef struct Suffix Suffix; Xstruct Suffix { X const Suffix *next; X long amount; X char *name; X}; X Xstatic const Suffix X kbsuf = { NULL, 1024, "k" }, X mbsuf = { &kbsuf, 1024*1024, "m" }, X gbsuf = { &mbsuf, 1024*1024*1024, "g" }, X stsuf = { NULL, 1, "s" }, X mtsuf = { &stsuf, 60, "m" }, X htsuf = { &mtsuf, 60*60, "h" }; X#define SIZESUF &gbsuf X#define TIMESUF &htsuf X Xtypedef struct { X char *name; X int flag; X const Suffix *suffix; X} Limit; Xstatic const Limit limits[] = { X { "cputime", RLIMIT_CPU, TIMESUF }, X { "filesize", RLIMIT_FSIZE, SIZESUF }, X { "datasize", RLIMIT_DATA, SIZESUF }, X { "stacksize", RLIMIT_STACK, SIZESUF }, X { "coredumpsize", RLIMIT_CORE, SIZESUF }, X { "memoryuse", RLIMIT_RSS, SIZESUF }, X { NULL, 0, NULL } X}; X Xextern int getrlimit(int, struct rlimit *); Xextern int setrlimit(int, struct rlimit *); X Xstatic void printlimit(const Limit *limit, boolean hard) { X struct rlimit rlim; X long lim; X getrlimit(limit->flag, &rlim); X if (hard) X lim = rlim.rlim_max; X else X lim = rlim.rlim_cur; X if (lim == RLIM_INFINITY) X fprint(1, "%s \tunlimited\n", limit->name); X else { X const Suffix *suf; X for (suf = limit->suffix; suf != NULL; suf = suf->next) X if (lim % suf->amount == 0) { X lim /= suf->amount; X break; X } X fprint(1, "%s \t%d%s\n", limit->name, lim, suf == NULL ? "" : suf->name); X } X} X Xstatic long parselimit(const Limit *limit, char *s) { X int len = strlen(s); X long lim = 1; X const Suffix *suf = limit->suffix; X if (streq(s, "unlimited")) X return RLIM_INFINITY; X if (suf == TIMESUF && strchr(s, ':') != NULL) { X char *t = strchr(s, ':'); X *t++ = '\0'; X lim = 60 * a2u(s) + a2u(t); X } else { X for (; suf != NULL; suf = suf->next) X if (streq(suf->name, s + len - strlen(suf->name))) { X s[len - strlen(suf->name)] = '\0'; X lim *= suf->amount; X break; X } X lim *= a2u(s); X } X if (lim < 0) X rc_error("bad limit"); X return lim; X} X Xstatic void b_limit(char **av) { X const Limit *lp = limits; X boolean hard = FALSE; X X if (*++av != NULL && streq(*av, "-h")) { X av++; X hard = TRUE; X } X X if (*av == NULL) { X for (; lp->name != NULL; lp++) X printlimit(lp, hard); X return; X } X X for (;; lp++) { X if (lp->name == NULL) X rc_error("no such limit"); X if (streq(*av, lp->name)) X break; X } X X if (*++av == NULL) X printlimit(lp, hard); X else { X struct rlimit rlim; X getrlimit(lp->flag, &rlim); X if (hard) X rlim.rlim_max = parselimit(lp, *av); X else X rlim.rlim_cur = parselimit(lp, *av); X if (setrlimit(lp->flag, &rlim) == -1) X uerror("setrlimit"); X } X} X#endif END_OF_FILE if test 10271 -ne `wc -c <'builtins.c'`; then echo shar: \"'builtins.c'\" unpacked with wrong size! fi # end of 'builtins.c' fi if test -f 'hash.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'hash.h'\" else echo shar: Extracting \"'hash.h'\" \(1175 characters\) sed "s/^X//" >'hash.h' <<'END_OF_FILE' Xtypedef struct Function { X Node *def; X char *extdef; X} Function; X Xtypedef struct Variable { X List *def; X char *extdef; X struct Variable *n; X} Variable; X Xtypedef struct Htab { X char *name; X void *p; X} Htab; X Xextern Htab *fp, *vp; X X#define lookup_fn(s) ((Function *) lookup(s,fp)) X#define lookup_var(s) ((Variable *) lookup(s,vp)) X Xextern void *lookup(char *, Htab *); Xextern Function *get_fn_place(char *); Xextern List *varlookup(char *); Xextern Node *fnlookup(char *); Xextern Variable *get_var_place(char *, boolean); Xextern boolean varassign_string(char *); Xextern char **makeenv(void); Xextern char *fnlookup_string(char *); Xextern char *varlookup_string(char *); Xextern void alias(char *, List *, boolean); Xextern void starassign(char *, char **, boolean); Xextern void delete_fn(char *); Xextern void delete_var(char *, boolean); Xextern void fnassign(char *, Node *); Xextern void fnassign_string(char *); Xextern void fnrm(char *); Xextern void initenv(char **); Xextern void inithash(void); Xextern void setsigdefaults(void); Xextern void inithandler(void); Xextern void varassign(char *, List *, boolean); Xextern void varrm(char *, boolean); Xextern void whatare_all_vars(void); END_OF_FILE if test 1175 -ne `wc -c <'hash.h'`; then echo shar: \"'hash.h'\" unpacked with wrong size! fi # end of 'hash.h' fi if test -f 'rc.1' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'rc.1'\" else echo shar: Extracting \"'rc.1'\" \(30362 characters\) sed "s/^X//" >'rc.1' <<'END_OF_FILE' X.\" rc.1 X.\" Dd distance to space vertically before a "display" X.\" These are what n/troff use for interparagraph distance X.if t .nr Dd .4v X.if n .nr Dd 1v X.\" Ds begin a display X.de Ds X.RS \\$1 X.sp \\n(Ddu X.nf X.. X.\" De end a display (no trailing vertical spacing) X.de De X.fi X.RE X.. X.ds Cf C X.de Cw X.lg 0 X\%\&\\$3\f\\*(Cf\\$1\f1\&\\$2 X.lg X.. X.TH RC 1 "28 April 1991" X.SH NAME Xrc \- shell X.SH SYNOPSIS X.B rc X[ X.B \-eixvld X] [ X.B -c X.I command X] [ X.I arguments X] X.SH DESCRIPTION X.I rc Xis a command interpreter and programming language similar to X.IR sh (1). XIt is based on the AT&T plan 9 shell of the same name. XThe shell offers a C-like syntax (much more so than the C shell), Xand a powerful mechanism for manipulating variables. XIt is reasonably small and reasonably fast, Xespecially when compared to contemporary shells. XIts use is intended to be interactive, Xbut the language lends itself well to scripts. X.SH OPTIONS X.TP X.B \-e XIf the X.Cw \-e Xoption is present, then X.I rc Xwill exit if the exit status of a command is false (nonzero). X.I rc Xwill not exit, however, if a conditional fails, e.g., an X.Cw if() Xcommand. X.TP X.B \-i XIf the X.Cw \-i Xoption is present or if the input to X.I rc Xis from a terminal (as determined by X.IR isatty (3)) Xthen X.I rc Xwill be in X.I interactive Xmode. XThat is, a prompt (from X.Cw $prompt(1) Xwill be printed before an Xinput line is taken, and X.I rc Xwill ignore the signals X.Cw SIGINT Xand X.Cw SIGQUIT . X.TP X.B \-x XThis option will make X.I rc Xprint every command on standard error before it is executed. XIt can be useful for debugging X.I rc Xscripts. X.TP X.B \-v XThis option will echo input to X.I rc Xon standard error as it is read. X.TP X.B \-l XIf the X.Cw \-l Xoption is present, or if X.IR rc 's X.Cw argv[0][0] Xis a dash X.Cw - ), ( Xthen X.I rc Xwill behave as a login shell. XThat is, it will try to run commands present in X.Cw $home/.rcrc , Xif this file exists, before reading any other input. X.TP X.B \-d XThis flag causes X.I rc Xnot to trap X.Cw SIGQUIT , Xand thus X.I rc Xwill dump core when it receives this signal. XThis option is only useful for debugging X.IR rc . X.TP X.B \-c XIf X.Cw \-c Xis present, commands are executed from the immediately following Xargument. XAny further arguments to X.I rc Xare placed in X.Cw $* . X.PP X.SH COMMANDS XA simple command is a sequence of words, separated by white space X(space and tab) characters that ends with a newline, semicolon X.Cw ; ), ( Xor ampersand X.Cw & ). ( XThe first word of a command is the name of that command. XIf the name begins with X.Cw / , X.Cw ./ , Xor X.Cw ../ , Xthen the name is used as an absolute path Xname referring to an executable file. XOtherwise, the name of the command is looked up in a table Xof shell functions, builtin commands, Xor as a file in the directories named by X.Cw $path . X.SS "Background Tasks" XA command ending with a X.Cw & Xis run in the background; that is, Xthe shell returns immediately rather than waiting for the command to Xcomplete. XBackground commands have X.I /dev/null Xconnected to their standard input unless an explicit redirection for Xstandard input is used. X.SS "Subshells" XA command prefixed with an at-sign X.Cw @ ) ( Xis executed in a subshell. XThis insulates the parent shell from the effects Xof a X.B cd Xor a variable assignment. XFor example: X.Ds X.Cw "@ {cd ..; make} X.De X.PP Xwill run X.IR make (1) Xin the parent directory X.Cw .. ), ( Xbut leaves the shell running in the current directory. X.SS "Line continuation" XA long logical line may be continued over several physical lines by Xterminating each line (except the last) with a backslash X.Cw \e ). ( XThe backslash-newline sequence is treated as a space. XA backslash is not otherwise special to X.IR rc . X.SS Quoting X.IR rc Xinterprets several characters specially; special characters Xautomatically terminate words. XThe following characters are special: X.Ds X.Cw "# ; & | ^ $ = ` ' { } ( ) < >\fR X.De X.PP XThe single quote X.Cw ' ) ( Xprevents special treatment of any character other than itself. XAll characters, including control characters, newlines, Xand backslashes between two quote characters are treated as an Xuninterpreted string. XA quote character itself may be quoted by placing two quotes in a row. XThe minimal sequence needed to enter the quote character is X.Cw '''' . XThe empty string is represented by X.Cw '' . XThus: X.Ds X.Cw "echo 'What''s the plan, Stan?' X.De X.PP Xprints out X.Ds X.Cw "What's the plan, Stan? X.De X.SS Grouping XZero or more commands may be grouped within braces X.Cw { ' (` Xand X.Cw } '), ` Xand are then treated as one command. XBraces do not otherwise define scope; Xthey are used only for command grouping. XIn particular, be wary of the command: X.Ds X.Cw "for (i) { X.Cw " command X.Cw "} | command X.De X.PP XSince pipe binds tighter than X.BR for , Xthis command does not perform what the user expects it to. XInstead, enclose the whole X.B for Xstatement in braces: X.Ds X.Cw "{for (i) command} | command X.De X.PP XFortunately, X.IR rc 's Xgrammar is simple enough that a (confident) user can Xunderstand it by examining the skeletal yacc grammar Xat the end of this man page (see the section entitled XGRAMMAR). X.SS "Input and output" X.PP XThe standard output may be redirected to a file with X.Ds X.Cw "command > file" X.De X.PP Xand the standard input may be taken from a file with X.Ds X.Cw "command < file X.De X.PP XFile descriptors other than 0 and 1 may be specified also. XFor example, to redirect standard error to a file, use: X.Ds X.Cw "command >[2] file X.De X.PP XIn order to duplicate a file descriptor, use X\f\*(Cf>[\fIn\f\*(Cf=\fIm\f\*(Cf]\fR. XThus to redirect both standard output and standard error Xto the same file, use X.Ds X.Cw "command > file >[2=1] X.De X.PP XTo close a file descriptor that may be open, use X\f\*(Cf>[\fIn\f\*(Cf=]\fR. XFor example, to Xclose file-descriptor 7: X.Ds X.Cw "command >[7=] X.De X.PP XIn order to place the output of a command at the end of an already Xexisting file, use: X.Ds X.Cw "command >> file X.De X.PP XIf the file does not exist, then it is created. X.PP X``Here documents'' are supported as in X.IR sh (1) Xwith the use of X.Ds X.Cw "command << 'eof-marker' X.De X.PP XIf the end-of-file marker is enclosed in quotes, then no variable substitution Xoccurs inside the here document. XOtherwise, every variable is Xsubstituted by its space-separated-list value (see Flat Lists, below), Xand if a X.Cw ^ Xcharacter follows a variable name, it is deleted. XThis allows the unambiguous use of variables adjacent to text, as in X.Ds X.Cw $variable^follow X.De X.PP XAdditionally, X.I rc Xsupports ``here strings'', which are like here documents, except that input Xis taken directly from a string on the command line. Its use is illustrated Xhere: X.Ds X.Cw "cat <<< 'this is a here string' | wc X.De X.PP X(This feature enables X.I rc Xto export functions using here documents into the environment; the author Xdoes not expect users to find this feature useful.) X.SS Pipes XTwo or more commands may be combined in a pipeline by placing the Xvertical bar X.Cw | ) ( Xbetween them. XThe standard output (file descriptor 1) Xof the command on the left is tied to the standard input (file Xdescriptor 0) of the command on the right. XThe notation X\f\*(Cf|[\fIn\f\*(Cf=\fIm\f\*(Cf]\fR Xindicates that file descriptor X.I n Xof the left process is connected to Xfile descriptor X.I m Xof the right process. X\f\*(Cf|[\fIn\f\*(Cf]\fR Xis a shorthand for X\f\*(Cf|[\fIn\f\*(Cf=0]\fR. XAs an example, to pipe the standard error of a command to X.IR wc (1), Xuse: X.Ds X.Cw "command |[2] wc X.De X.SS "Commands as Arguments" XSome commands, like X.IR cmp (1) Xor X.IR diff (1), Xtake their arguments on the command Xline, and do not read input from standard input. XIt is convenient Xsometimes to build nonlinear pipelines so that a command like cmp can Xread the output of two other commands at once. X.I rc Xdoes it like this: X.Ds X.Cw "cmp <{command} <{command} X.De X.PP Xcompares the output of the two commands in braces. XA note: since this form of Xredirection is implemented with named pipes, and since one cannot X.IR lseek (2) Xon a pipe, commands that use X.IR lseek (2) Xwill hang. XFor example, Xmost versions of X.IR diff (1) Xuse X.IR lseek (2) Xon their inputs. X.SH "CONTROL STRUCTURES" XThe following may be used for control flow in X.IR rc : X.SS "If-else Statements" X.PD 0 X.sp X\fBif (\fItest\fB) { X.br X.B " " \fIcmd\fB X.br X.TP X.B } else \fIcmd\fB XThe X.I test Xis executed, and if its return status is zero, the first Xcommand is executed, otherwise the second is. XBraces are not mandatory around the commands. XHowever, an else statement is valid only if it Xfollows a close-brace on the same line. XOtherwise, the if is taken to be a simple-if: X.Ds X.Cw "if (test) X.Cw " command X.De X.PD X.SS "While and For Loops" X.TP X.B while (\fItest\fB) \fIcmd\fB X.I rc Xexecutes the X.I test Xand performs the command as long as the X.I test Xis true. X.TP X.B for (\fIvar\fB in \fIlist\fB) \fIcmd\fB X.I rc Xsets X.I var Xto each element of X.I list X(which may contain variables and backquote substitutions) and runs X.IR cmd . XIf ``\fBin\fR \fIlist\fR'' is omitted, then X.I rc Xwill set X.I var Xto each element of X.Cw $* X(excluding X.Cw $0 . XFor example: X.Ds X.Cw "for (i in `{ls -F | grep '\e*$' | sed 's/\e*$//'}) { commands } X.De X.PP Xwill set X.Cw $i Xto the name of each file in the current directory which is Xexecutable. X.SS "Switch" X.TP X.B switch (\fIlist\fB) { case \fR...\fB } X.I rc Xlooks inside the braces after a X.B switch Xstatement for single lines beginning with the word X.BR case . XIf any of the patterns following X.B case Xmatch the list supplied to X.BR switch , Xthen the commands up until the next X.B case Xstatement are executed. XMetacharacters should not be quoted; Xmatching is performed only against the strings in X.IR list , Xnot against file names. X(Matching for case statements is the same as for the X.Cw ~ Xcommand.) X.SS "Logical Operators" XThere are a number of operators in X.I rc Xwhich depend on the exit status of a command. X.Ds X.Cw "command && command X.De X.PP Xexecutes the first command and then executes the second command if and only if Xthe first command exits with a zero exit status (``true'' in UNIX). X.Ds X.Cw "command || command X.De X.PP Xexecutes the first command executing the second command if and only if Xthe second command exits with a nonzero exit status (``false'' in UNIX). X.Ds X.Cw "! command X.De X.PP Xnegates the exit status of a command. XThus: X.Ds X.Cw "! command || command X.De X.PP Xis equivalent to X.Ds X.Cw "command && command X.De X.SH "PATTERN MATCHING" XThere are two forms of pattern matching in X.IR rc . XOne is traditional shell globbing. XThis occurs in matching for file names in argument lists: X.Ds X.Cw "command argument argument ... X.De X.PP XWhen the characters X.Cw "*" , X.Cw [ Xor X.Cw ? Xoccur in an argument, X.I rc Xlooks at the Xargument as a pattern for matching against files according to the Xfollowing rules: a X.Cw * Xmatches any number (including zero) of Xcharacters. XA X.Cw ? Xmatches any single character, and a X.Cw [ Xfollowed by a Xnumber of characters followed by a X.Cw ] Xmatches a single character in that Xclass. XThe rules for character class matching are the same as those for X.IR ed (1), Xwith the exception that character class negation is achieved Xwith the tilde X.Cw ~ ), ( Xnot the caret X.Cw ^ ), ( Xsince the caret already means Xsomething else in X.IR rc . X.PP X.I rc Xalso matches patterns against strings with the X.Cw ~ Xcommand: X.Ds X.Cw "~ subject pattern pattern ... X.De X.PP X.Cw ~ Xsets X.Cw $status Xto zero if and only if a supplied pattern matches any Xsingle element of the subject list. XThus X.Ds X.Cw "~ foo f* X.De X.PP Xsets status to zero, while X.Ds X.Cw "~ (bar baz) f* X.De X.PP Xsets status to one. XThe null list is matched by the null list, so X.Ds X.Cw "~ $foo () X.De X.PP Xchecks to see whether X.Cw $foo Xis empty or not. XThis may also be achieved Xby the test X.Ds X.Cw "~ $#foo 0 X.De X.PP XNote that inside a X.Cw ~ Xcommand X.I rc Xdoes not match patterns against file Xnames, so it is not necessary to quote the characters X.Cw "*" , X.Cw [ Xand X.Cw "?" . XFinally, note that if the X.Cw ~ Xcommand is given a list as its first Xargument, then a successful match against any of the elements of that Xlist will cause X.Cw ~ Xto return true. XFor example: X.Ds X.Cw "~ (foo goo zoo) z* X.De X.PP Xis true. X.SH "LISTS AND VARIABLES" XThe primary data structure in X.IR rc Xis the list, which is a sequence of words. XParentheses are used to group lists. XThe empty list is represented by X.Cw "()" . XLists have no hierarchical structure; Xa list inside another list is expanded so the Xouter list contains all the elements of the inner list. XThus, the following are all equivalent X.Ds X.Cw "one two three X X.Cw "(one two three) X X.Cw "((one) () ((two three))) X.De X.PP XNote that the null string, X.Cw "''" , Xand the null list, X.Cw "()" , Xare two very Xdifferent things. XAssigning the null string to variable is a valid Xoperation, but it does not remove its definition. XFor example, Xif X.Cw $a Xis set to X.Cw "''" , Xthen X.Cw "$#a" , Xreturns a 1. X.SS "List Concatenation" XTwo lists may be joined by the concatenation operator X.Cw ^ ). ( XA single word is treated as a list of length one, so X.Ds X.Cw "echo foo^bar X.De X.PP Xproduces the output X.Ds X.Cw foobar X.De X.PP XFor lists of more than one element, Xconcatenation works according to the following rules: if the two lists Xhave the same number of elements, then concatenation is pairwise: X.Ds X.Cw "echo (a\- b\- c\-)^(1 2 3) X.De X.PP Xproduces the output X.Ds X.Cw "a\-1 b\-2 c\-3 X.De X.PP XOtherwise, one of the lists must have a single element, and then the Xconcatenation is distributive: X.Ds X.Cw "cc \-^(O g c) (malloc alloca)^.c X.De X.PP Xhas the effect of performing the command X.Ds X.Cw "cc \-O \-g \-c malloc.c alloca.c X.De X.SS "Free Carets" X.I rc Xinserts carets (concatenation operators) for free in certain Xsituations, in order to save some typing on the user's behalf. XFor Xexample, the above example could also be typed in as: X.Ds X.Cw "opts=(O g c) files=(malloc alloca) cc \-$opts $files.c X.De X.PP X.I rc Xtakes care to insert a free-caret between the X.Cw \- ' ` Xand X.Cw "$opts" , Xas well Xas between X.Cw $files Xand X.Cw ".c" . XThe rule for free carets is as follows: if Xa word or keyword is immediately Xfollowed by another word, keyword, dollar-sign or Xbackquote, then X.I rc Xinserts a caret between them. X.SS "Variables" XA list may be assigned to a variable, using the notation: X.Ds X.Cw "var = list X.De X.PP XAny sequence of non-special characters, except a sequence including Xonly digits, may be used as a variable name. XAll user-defined variables are exported into the environment. X.PP XThe value of a variable is referenced with the notation: X.Ds X.Cw $var X.De X.PP XAny variable which has not been assigned a value returns the null list, X.Cw "()" , Xwhen referenced. In addition, multiple references are allowed: X.Ds X.Cw a=foo X.Cw b=a X.Cw echo $$b X.De X.PP Xprints X.Ds X.Cw foo X.De X.PP XA variable's definition may also be removed by Xassigning the null list to a variable: X.Ds X.Cw var=() X.De X.PP XFor ``free careting'' to work correctly, X.I rc Xmust make certain assumptions Xabout what characters may appear in a variable name. X.I rc Xcurrently Xassumes that a variable name consists only of alphanumeric characters, Xunderscore X.Cw _ ) ( Xand star X.Cw * ). ( XTo reference a variable with other Xcharacters in its name, quote the variable name. XThus: X.Ds X.Cw "echo $'we$Ird\Variab!le' X.De X.SS "Local Variables" XAny number of variable assignments may be made local to a single Xcommand by typing: X.Ds X.Cw "a=foo b=bar ... command X.De X.PP XThe command may be a compound command, so for example: X.Ds X.Cw "path=. ifs=() { X.Cw ... X.De X.PP Xsets path to X.Cw . Xand ifs to X.Cw () Xfor the duration of one long compound Xcommand. X.SS "Variable Subscripts" XVariables may be subscripted with the notation X.Ds X\f\*(Cf$var(\fIn\f\*(Cf\fR) X.De X.PP Xwhere X.I n Xis a list of integers (origin 1). XThe list of subscripts need Xnot be in order or even unique. XThus, if X.Ds X.Cw "a=(one two three) X.De X.PP Xthen X.Ds X.Cw "echo $a(3 3 3) X.De X.PP Xprints X.Ds X.Cw "three three three X.De X.PP XIf X.I n Xreferences a nonexistent element, then X\f\*(Cf$var(\fIn\f\*(Cf\fR) Xreturns the null Xlist. XThe notation X.Cw "$\fIn" , Xwhere X.I n Xis an integer, is a shorthand for X\f\*(Cf$*(\fIn\f\*(Cf)\fR. XThus, X.IR rc 's Xarguments may be referred to as X.Cw "$1" , X.Cw "$2" , Xand so on. X.PP XNote also that the list of subscripts may be given by any of X.IR rc 's Xlist operations: X.Ds X.Cw "$var(`{awk 'BEGIN{for(i=1;i<=10;i++)print i;exit; }'}) X.De X.PP Xreturns the first 10 elements of X.Cw $var . X.PP XTo count the number of elements in a variable, use X.Ds X.Cw $#var X.De X.PP XThis returns a single-element list, with the number of elements in X.Cw $var . X.SS "Flat Lists" XIn order to create a single-element list from a multi-element list, Xwith the components space-separated, use X.Ds X.Cw $^var X.De X.PP XThis is useful when the normal list concatenation rules need to be Xbypassed. XFor example, to append a single period at the end of X.Cw $path , Xuse: X.Ds X.Cw "echo $^path. X.De X.SS "Backquote Substitution" XA list may be formed from the output of a command by using backquote Xsubstitution: X.Ds X.Cw "`{ command } X.De X.PP Xreturns a list formed from the standard output of the command in braces. X.Cw $ifs Xis used to split the output into list elements. XBy default, X.Cw $ifs Xhas the value space-tab-newline. XThe braces may be omitted if the command is a single word. XThus X.Cw `ls Xmay be used instead of X.Cw "`{ls}" . XThis last feature is useful when defining functions that expand Xto useful argument lists. A frequent use is: X.Ds X.Cw "fn src { echo *.[chy] } X.De X.PP Xfollowed by X.Ds X.Cw "wc `src X.De X.PP X(This will print out a word-count of all C source files in the current Xdirectory.) X.PP XIn order to override the value of X.Cw $ifs Xfor a single backquote Xsubstitution, use: X.Ds X.Cw "`` (ifs-list) { command } X.De X.PP X.Cw $ifs Xwill be temporarily ignored and the command's output will be split as specified by Xthe list following the double backquote. XFor example: X.Ds X.Cw "`` ($nl :) {cat /etc/passwd} X.De X.PP Xsplits up X.I /etc/passwd Xinto fields, assuming that X.Cw $nl Xcontains a newline Xas its value. X.SH "SPECIAL VARIABLES" XSeveral variables are known to X.I rc Xand are treated specially. X.TP X.B * XThe argument list of X.IR rc . X.Cw "$1, $2, Xetc. are the same as X.Cw $*(1) , X.Cw $*(2) , Xetc. XThe variable X.Cw $0 Xholds the value of X.Cw argv[0] Xwith which X.I rc Xwas invoked. XAdditionally, X.Cw $0 Xis set to the name of a function for the duration of Xthe execution of that function, and X.Cw $0 Xis also set to the name of the Xfile being interpreted for the duration of a X.Cw . Xcommand. X.TP X.B apid XThe process ID of the last process started in the background. X.TP X.B cdpath XA list of directories to search for the target of a X.B cd Xcommand. XThe empty string stands for the current directory. Note that Xan assignment to X.Cw $cdpath Xcauses an automatic assignment to X.Cw $CDPATH , Xand vice-versa X.TP X.B history X.Cw $history Xcontains the name of a file to which commands are appended as X.I rc Xreads them. XThis facilitates the use of a stand-alone history program Xwhich parses the contents of the history file and presents them to X.I rc Xfor reinterpretation. XIf X.Cw $history Xis not set, then X.I rc Xdoes not append commands to any file. X.TP X.B home XThe default directory for the builtin cd command and is the directory Xin which X.I rc Xlooks to find its initialization file, X.IR .rcrc , Xif X.I rc Xhas been started up as a login shell. Like X.Cw $cdpath Xand X.Cw $CDPATH , X.Cw $home Xand X.Cw $HOME Xare aliased to each other. X.TP X.B ifs XThe internal field separator, used for splitting up the output of Xbackquote commands for digestion as a list. X.TP X.B path XThis is a list of directories to search in for commands. XThe empty string stands for the current directory. Note that Xlike X.Cw $cdpath Xand X.Cw $CDPATH , X.Cw $path Xand X.Cw $PATH Xare aliased to each other. X.TP X.B pid XThe process ID of the currently running X.IR rc . X.TP X.B prompt XThis variable holds the two prompts (in list form, of course) that X.I rc Xprints. X.Cw $prompt(1) Xis printed before each command is read, and X.Cw $prompt(2) Xis printed when input is expected to continue on the next Xline. X.I rc Xsets X.Cw $prompt Xto X.Cw "('; ' '') Xby default. XThe reason for this is that it enables an X.I rc Xuser to grab commands from previous lines using a Xmouse, and to present them to X.I rc Xfor re-interpretation; the semicolon Xprompt is simply ignored by X.IR rc . XThe null X.Cw $prompt(2) Xalso has its Xjustification: an X.I rc Xscript, when typed interactively, will not leave X.Cw $prompt(2) 's Xon the screen, Xand can therefore be grabbed by a mouse and placed Xdirectly into a file for use as a shell script, without further editing Xbeing necessary. X.TP X.B prompt (function) XIf this function is set, then it gets executed every time X.I rc Xis about to print X.Cw "$prompt(1)" . X.TP X.B status XThe exit status of the last command. XIf the command exited with a numeric value, Xthat number is the status. XIf the died with a signal, Xthe status is the name of that signal; if a core file Xwas created, the string X.Cw +core '' `` Xis appended. XThe value of X.Cw $status Xfor a pipeline is a list, with one entry, Xas above, for each process in the pipeline. XFor example, the command X.Ds 1i X.Cw "ls | wc X.De X.TP X\& Xusually sets X.Cw $status Xto X.Cw "(0 0)" . X.PP XThe values of X.Cw "$path" , X.Cw "$cdpath" , Xand X.Cw $home Xare derived from the environment Xvalues of X.Cw "$PATH" , X.Cw "$CDPATH" , Xand X.Cw "$HOME" . XOtherwise, they are derived from Xthe environment values of X.Cw $path , X.Cw $cdpath Xand X.Cw $home . XThis is for compatibility with other UNIX programs, like X.IR sh (1). X.Cw $PATH Xand X.Cw $CDPATH Xare assumed to be colon-separated lists. X.SH FUNCTIONS X.I rc Xfunctions are identical to X.I rc Xscripts, except that they are stored Xin memory and are automatically exported into the environment. XA shell function is declared as: X.Ds X.Cw "fn name { commands } X.De X.PP X.I rc Xscans the definition in until the close-brace, so the function can Xspan more than one line. XThe function definition may be removed by typing X.Ds X.Cw "fn name X.De X.PP XWhen a function is executed, X.Cw $* Xis set to the arguments to that Xfunction for the duration of the command. XThus a reasonable definition for X.Cw "l" , Xa shorthand for X.IR ls (1), Xcould be: X.Ds X.Cw "fn l { ls -FC $* } X.De X.PP Xbut not X.Ds X.Cw "fn l { ls -FC } X.De X.SH "INTERRUPTS AND SIGNALS" X.I rc Xrecognizes a number of signals, and allows the user to define shell Xfunctions which act as signal handlers. X.I rc Xby default traps X.Cw SIGINT Xand X.Cw SIGQUIT Xwhen it is interactive mode. X.Cw SIGQUIT Xis ignored, unless X.I rc Xhas been invoked with the X.Cw \-d Xflag. XHowever, user-defined signal handlers may be written for these and Xall other signals. XThe way to define a signal handler is to Xwrite a function by the name of the signal in lower case. XThus: X.Ds X.Cw "fn sighup { echo hangup; rm /tmp/rc$pid.*; exit } X.De X.PP XIn addition to Unix signals, rc recognizes the artificial signal X.Cw SIGEXIT Xwhich occurs as rc is about to exit. X.PP XIn order to remove a signal handler's definition, remove it as though Xit were a regular function. XFor example: X.Ds X.Cw "fn sigint X.De X.PP Xreturns the handler of X.Cw SIGINT Xto the default value. XIn order to ignore a signal, set the signal handler's value to X.Cw "{}" . XThus: X.Ds X.Cw "fn sigint {} X.De X.PP Xcauses SIGINT to be ignored by the shell. X.SH "BUILTIN COMMANDS" XBuiltin commands execute in the context of the shell, but otherwise Xbehave exactly like other commands. X.TP X.B . \fR[\fB\-i\fR]\fB \fIfile args\fB XReads \fIfile\fP as input to X.IR rc Xand executes its contents. XWith a X.Cw \-i Xflag, input is interactive. XThus Xfrom within a shell script, X.Ds 1i X.Cw ". \-i /dev/tty X.De X.TP X\& Xdoes the ``right'' thing. X.TP X.B break XBreaks from the innermost X.B for Xor X.BR while , Xas in C. XIt is an error to Xinvoke X.B break Xoutside of a loop. X(Note that Xthere is no X.B break Xkeyword between Xcommands in X.B switch Xstatements, unlike C.) X.TP X.B builtin \fIcommand ...\fB XExecutes the command as a builtin; no function lookup or directory Xsearching is done. XThis command is present to allow functions with the Xsame names as builtins to use the underlying builtin. X.TP X.B cd \fIdirectory\fB XChange the current directory. XThe variable X.Cw $cdpath Xis searched for Xpossible locations of \fIdirectory\fP, analogous to the searching of X.Cw $path Xfor executable files. XWith no argument, X.B cd Xchanges directory to X.Cw "$home" . X.TP X.B echo \fIargs ...\fB XPrints its arguments to standard output. XArguments are separated by spaces. XIf the first argument is X.Cw "\-n" , Xno final newline is printed. XIf the first argument is X.Cw "\-\-" , Xthen any subsequent arguments are ignored. X.TP X.B eval \fIlist\fB X.B eval Xconcatenates the elements of X.I list Xwith spaces and feeds the resulting string to X.I rc Xfor re-scanning. XThis is the only time input is rescanned in X.IR rc . X.TP X.B exec \fIcommand\fB Xreplaces X.I rc Xwith the given command. XIf the exec contains only redirections, Xthen these redirections apply to the current shell Xand the shell does not exit. XFor example, X.Ds 1i X.Cw "exec >[2] err.out X.De X.TP X\& Xplaces further output to standard error in the file X.IR err.out . X.TP X.B exit \fIstatus\fB XCause the current shell to exit with the given exit X.IR status . XIf no argument is given, the current value of X.Cw $status Xis used. X.TP X.B limit \fR[\fB\-h\fR]\fB \fR[\fIresource\fR]\fB \fR[\fIvalue\fR]\fB XSimilar to the X.IR csh (1) Xlimit builtin, this command operates upon the XBSD-style limits of a process. XThe X.Cw \-h Xflag displays/alters the hard Xlimits. XThe resources which can be shown or altered are X.BR cputime , X.BR filesize , X.BR datasize , X.BR stacksize , X.B coredumpsize Xand X.BR memoryuse . XFor Xexample: X.Ds 1i X.Cw "limit coredumpsize 0 X.De X.TP X\& Xdisables core dumps. X.TP X.B return \fIn\fB XReturns from the current function, with status X.IR n . XIf X.IR n Xis omitted, then X.Cw $status Xis left unchanged. XIt is an error to invoke X.B return Xwhen not inside a function. X.TP X.B shift \fIn\fB XDeletes X.I n Xelements from the beginning of X.Cw $* Xand shifts the other Xelements down by X.IR n . X.I n Xdefaults to 1. X(Note that X.Cw $0 Xis not affected by X.BR shift .) X.TP X.B umask \fImask\fB XSets the current umask (see X.IR umask (2)) Xto the octal X.IR mask . XIf no argument is present, the current mask value is printed. X.TP X.B wait \fIpid\fB XWaits for the specified X.IR pid , Xwhich must have been started by X.IR rc . XIf no X.I pid Xis specified, X.I rc Xwaits for any child process to exit. X.TP X.B whatis \fIname ...\fB XPrints a definition of the named objects. XFor variables, their values Xare printed; for functions, their definitions are; and for executable Xfiles, path names are printed. XWithout arguments, X.B whatis Xprints the values of all shell variables and functions. Note that X.B whatis Xoutput is suitable for input to X.IR rc ; Xby saving the output of X.B whatis Xin a file, it should be possible to recreate the state of X.I rc Xby sourcing this file with a X.Cw . Xcommand. X.SH GRAMMAR XHere is X.IR rc 's Xgrammar, edited to remove semantic actions. X.Ds X\f\*(Cf X%term BANG DUP ELSE END FN FOR HUH IF IN LBRACK PIPE RBRACK X%term REDIR STAR SUB SUBSHELL SWITCH TWIDDLE WHILE WORD X X%left IF WHILE FOR SWITCH ')' ELSE X%left ANDAND OROR X%left BANG SUBSHELL X%left PIPE X%left '^' X%right '$' COUNT FLAT X%left SUB X%left '`' BACKBACK X X%% X Xrc: line end | error end X Xend: '\en' | END X Xcmdsa: cmd ';' | cmd '&' X Xline: cmd | cmdsa line X Xbody: cmd | cmdsan body X Xcmdsan: cmdsa | cmd '\en' X Xbrace: '{' body '}' X Xparen: '(' body ')' X Xassign: first '=' word X Xepilog: /* empty */ | redir epilog X Xredir: DUP | REDIR word X Xiftail: cmd %prec IF | brace ELSE cmd X Xcmd : /* empty */ X | simple X | brace epilog X | IF paren { skipnl(); } iftail X | FOR '(' word IN words ')' { skipnl(); } cmd X | FOR '(' word ')' { skipnl(); } cmd X | WHILE paren { skipnl(); } cmd X | SWITCH '(' word ')' { skipnl(); } brace X | TWIDDLE word words X | cmd ANDAND { skipnl(); } cmd X | cmd OROR { skipnl(); } cmd X | cmd PIPE { skipnl(); } cmd X | redir cmd %prec BANG X | assign cmd %prec BANG X | BANG cmd X | SUBSHELL cmd X | FN words brace X | FN words X Xsimple: first | simple word | simple redir X Xfirst: comword | first '^' word X Xword: comword | keyword | word '^' word X Xcomword: WORD X | COUNT word | FLAT word X | '`' word | '`' brace X | BACKBACK word brace | BACKBACK word word X | '(' words ')' X | REDIR brace X | '$' word | '$' word SUB words ')' X Xkeyword: FOR | IN | WHILE | IF | SWITCH X | FN | ELSE | TWIDDLE | BANG | SUBSHELL X Xwords: /* empty */ | words word X\fR X.De X.SH FILES X.I "$HOME/.rcrc, /tmp/rc*, /dev/null X.SH CREDITS X.I rc Xwas written by Byron Rakitzis, with valuable help Xfrom Paul Haahr, Hugh Redelmeier and David Sanderson. XThe design of this shell has been copied from the rc Xthat Tom Duff wrote at Bell Labs. X.SH BUGS X.Cw <{foo} Xstyle redirection is implemented with named pipes, and it is sometimes Xpossible to foil rc into removing the FIFO it places in X.I /tmp Xprematurely, or it is even possible to cause rc to hang. This redirection Xshould be implemented via X.I /dev/fd Xon systems which have it. X.B XThe functionality of X.B shift Xshould be available for variables other than X.Cw "$*" . X.PP X.B echo Xis built in only for performance reasons, which is a bad idea. X.PP XThere should be a way to avoid exporting a variable. X.PP XThe X.Cw $^var Xnotation for flattening should allow for using an arbitrary Xseparating character, not just space. X.PP XBug reports should be mailed to X.Cw "byron@archone.tamu.edu" . X.SH INCOMPATIBILITIES XHere is a list of features which distinguish this incarnation of X.I rc Xfrom the one described in the Bell Labs manual pages: X.PP XThe treatment of if-else is different in the v10 X.IR rc : Xthat version uses Xan ``if not'' clause which gets executed if the preceding ``if'' test Xdoes not succeed. X.PP XBackquotes are slightly different in v10 X.IR rc : Xa backquote must always be followed by Xa left-brace. XThis restriction is not present for single-word Xcommands in this X.IR rc . X.PP XThe following are all new with this version of X.IR rc : XThe list flattening operator, Xhere strings (they facilitate exporting of functions Xwith here documents into the environment), Xthe X.B return Xand X.B break Xkeywords, Xthe X.B echo Xbuiltin, Xthe support for the GNU X.IR readline (3) Xlibrary and Xthe support for the X.B prompt Xfunction. XThis X.I rc Xalso sets X.Cw $0 Xto the name of a function being executed/file Xbeing sourced. X.SH "SEE ALSO" X``rc \(em A shell for Plan 9 and UNIX'', XUnix Research System, X10th Edition, Xvol. 2. (Saunders College Publishing) END_OF_FILE if test 30362 -ne `wc -c <'rc.1'`; then echo shar: \"'rc.1'\" unpacked with wrong size! fi # end of 'rc.1' fi echo shar: End of archive 1 \(of 4\). cp /dev/null ark1isdone MISSING="" for I in 1 2 3 4 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have unpacked all 4 archives. rm -f ark[1-9]isdone else echo You still must unpack the following archives: echo " " ${MISSING} fi exit 0 exit 0 # Just in case... -- Kent Landfield INTERNET: kent@sparky.IMD.Sterling.COM Sterling Software, IMD UUCP: uunet!sparky!kent Phone: (402) 291-8300 FAX: (402) 291-4362 Please send comp.sources.misc-related mail to kent@uunet.uu.net.