Annotation of researchv10dc/vol2/rc/rc.ms, revision 1.1

1.1     ! root        1: .so ../ADM/mac
        !             2: .XX rc 283 "Rc \(em A Shell for Plan 9 and UNIX"
        !             3: .fp 5 T CW     \" T for Typewriter
        !             4: .Tm shell programming language g
        !             5: .de TP \" An indented paragraph describing some command, tagged with the command name
        !             6: .IP "\\fT\\$1\\fR" 5
        !             7: .if \\w'\\fT\\$1\\fR'-4n .br
        !             8: ..
        !             9: .de CI
        !            10: .nr Sf \\n(.f
        !            11: \%\&\\$3\f(CW\\$1\fI\&\\$2\f\\n(Sf
        !            12: ..
        !            13: .TL
        !            14: Rc \(em A Shell for Plan 9 and UNIX
        !            15: .AU
        !            16: Tom Duff
        !            17: .AI
        !            18: .MH
        !            19: .AB
        !            20: .I Rc
        !            21: is a command interpreter for Plan 9.
        !            22: It also runs on a variety of UNIX systems,
        !            23: including SunOS and the Tenth Edition.
        !            24: It provides similar facilities to Bourne's
        !            25: .I /bin/sh ,
        !            26: with some small additions and mostly less idiosyncratic syntax.
        !            27: This paper introduces
        !            28: .I rc
        !            29: with numerous examples, and discusses its design and
        !            30: why it varies from Bourne's.
        !            31: .AE
        !            32: .2C
        !            33: .NH
        !            34: Introduction
        !            35: .PP
        !            36: Plan 9 needs a command-programming language.  As porting the
        !            37: Bourne shell to a non-UNIX environment seemed a daunting task,
        !            38: I chose to write a new command interpreter, called
        !            39: .I rc
        !            40: because it runs commands.
        !            41: Although tinkering with perfection is a dangerous business,
        !            42: I could hardly resist trying to `improve' on Bourne's design.
        !            43: Thus,
        !            44: .I rc
        !            45: is similar in spirit, but different in detail from Bourne's
        !            46: shell.
        !            47: .NH
        !            48: Simple commands
        !            49: .PP
        !            50: For the simplest uses,
        !            51: .I rc
        !            52: has syntax familiar to Bourne shell users.
        !            53: A simple command is a blank-separated sequence of arguments.
        !            54: .P1
        !            55: date
        !            56: .P2
        !            57: prints the current date and time, and
        !            58: .P1
        !            59: con alice
        !            60: .P2
        !            61: connects the user's terminal to the machine
        !            62: .CW alice .
        !            63: .NH
        !            64: Quotation
        !            65: .PP
        !            66: An argument that contains a space or one of
        !            67: .I rc 's
        !            68: other syntax characters should be enclosed in apostrophes
        !            69: .CW ' ). (
        !            70: For example:
        !            71: .P1
        !            72: rm 'odd file name'
        !            73: .P2
        !            74: To include an apostrophe in a quoted name, it must be doubled:
        !            75: .P1
        !            76: echo 'How''s your father?'
        !            77: .P2
        !            78: .NH
        !            79: Comments and continuation
        !            80: .PP
        !            81: A number-sign
        !            82: .CW # ) (
        !            83: and all characters following it up to, but not including, the next newline
        !            84: are ignored, except in quotation marks.
        !            85: .PP
        !            86: A long command line may be continued on subsequent lines by typing a
        !            87: backslash
        !            88: .CW \e ) (
        !            89: followed immediately by a newline, anywhere that white space is required.
        !            90: Commands also continue onto the next line when the last symbol on
        !            91: a line could not reasonably be the end of the command.
        !            92: .NH
        !            93: I/O Redirection
        !            94: .PP
        !            95: Many commands write output on the standard output file, normally the terminal.
        !            96: A command's standard output may be made to overwrite a file by writing
        !            97: .P1
        !            98: who >user.names
        !            99: .P2
        !           100: This command produces a list of the currently logged in users in a file named
        !           101: .CW user.names .
        !           102: Standard output may be appended to the end of a file by
        !           103: .P1
        !           104: who >>user.names
        !           105: .P2
        !           106: In either case, mentioning a non-existent file causes it to be created.
        !           107: .PP
        !           108: Likewise, a command's standard input, also normally the terminal, may be connected to
        !           109: a file by
        !           110: .P1
        !           111: wc <file
        !           112: .P2
        !           113: This command will report the number of characters, lines and words in
        !           114: .CW file .
        !           115: ........
        !           116: .NH
        !           117: Pipelines
        !           118: .PP
        !           119: The standard output of one command may be connected to the standard input of another
        !           120: command like this:
        !           121: .P1
        !           122: who | wc
        !           123: .P2
        !           124: This prints the number of users currently logged in, and is equivalent to
        !           125: .P1
        !           126: who >tmp
        !           127: wc <tmp
        !           128: .P2
        !           129: except that no temporary file is produced.  Instead a pipe \(em an
        !           130: interprocess channel that looks to one process like an output file and to
        !           131: another like an input file \(em is created joining the two commands, which
        !           132: run simultaneously.  The pipe contains a data buffer so that the two
        !           133: commands need not produce and consume data in perfect lock-step.
        !           134: .NH
        !           135: Filename patterns
        !           136: .PP
        !           137: .I Rc
        !           138: has several ways to generate argument lists automatically.
        !           139: These include filename pattern matching, variable substitution, string concatenation,
        !           140: command substitution and pipeline branching.
        !           141: .PP
        !           142: Any literal word containing one of the meta-characters
        !           143: .CW * ,
        !           144: .CW ?
        !           145: or
        !           146: .CW [
        !           147: is a pattern used to match filenames.
        !           148: A
        !           149: .CW *
        !           150: matches any sequence of characters
        !           151: a
        !           152: .CW ?
        !           153: matches any single character,
        !           154: and a list of characters between
        !           155: .CW [
        !           156: and
        !           157: .CW ]
        !           158: matches a single character from the listed set.
        !           159: The list may include ranges like
        !           160: .CW a-z ,
        !           161: specifying all ASCII characters between the two.
        !           162: The entire set is complemented if the first character
        !           163: after
        !           164: .CW [
        !           165: is
        !           166: .CW ~
        !           167: (a tilde.)
        !           168: No meta-character can match
        !           169: the first character of the filenames
        !           170: .CW .
        !           171: and
        !           172: .CW ..
        !           173: or the character
        !           174: .CW / .
        !           175: .PP
        !           176: A pattern is replaced by a list of all the names that it matches.
        !           177: If it matches no name, it remains unreplaced.
        !           178: .PP
        !           179: Meta-characters are active only when they appear literally
        !           180: and unquoted.  For example, if a variable (see below) has a
        !           181: .CW *
        !           182: in it, and the value is substituted into a line, it is
        !           183: not used for filename matching.
        !           184: .NH
        !           185: Variables
        !           186: .PP
        !           187: .I Rc
        !           188: provides variables whose values are lists of arguments.
        !           189: Variables may be given values by typing, for example:
        !           190: .P1
        !           191: path=(. /bin /usr/bin)
        !           192: user=td
        !           193: tty=/dev/tty8
        !           194: .P2
        !           195: The parentheses indicate that the value assigned to
        !           196: .CW path
        !           197: is a list of three strings. The variables
        !           198: .CW user
        !           199: and
        !           200: .CW tty
        !           201: are assigned lists containing a single string.
        !           202: .PP
        !           203: The value of a variable can be substituted into a command by
        !           204: preceding its name with a
        !           205: .CW $ ,
        !           206: like this:
        !           207: .P1
        !           208: echo $path
        !           209: .P2
        !           210: If
        !           211: .CW path
        !           212: had been set as above, this would be equivalent to
        !           213: .P1
        !           214: echo . /bin /usr/bin
        !           215: .P2
        !           216: Variables may be subscripted by numbers or lists of numbers,
        !           217: like this:
        !           218: .P1
        !           219: echo $path(2)
        !           220: echo $path(3 2 1)
        !           221: .P2
        !           222: These are equivalent to
        !           223: .P1
        !           224: echo /bin
        !           225: echo /usr/bin /bin .
        !           226: .P2
        !           227: There can be no space separating the variable's name from the
        !           228: left parenthesis.  Otherwise, the subscript would be considered
        !           229: a separate parenthesized list.
        !           230: .PP
        !           231: The number of strings in a variable can be determined by the
        !           232: .CW $#
        !           233: operator.  For example,
        !           234: .P1
        !           235: echo $#path
        !           236: .P2
        !           237: would print the number of entries in
        !           238: .CW $path .
        !           239: .PP
        !           240: The following two assignments are subtly different:
        !           241: .P1
        !           242: empty=()
        !           243: null=''
        !           244: .P2
        !           245: The first sets
        !           246: .CW empty
        !           247: to a list containing no strings.
        !           248: The second sets
        !           249: .CW null
        !           250: to a list containing a single string,
        !           251: but the string contains no characters.
        !           252: .PP
        !           253: Although these may seem like more or less
        !           254: the same thing (in Bourne's shell, they are
        !           255: indistinguishable), they behave differently
        !           256: in almost all circumstances.
        !           257: Among other things
        !           258: .P1
        !           259: echo $#empty
        !           260: .P2
        !           261: prints 0, whereas
        !           262: .P1
        !           263: echo $#null
        !           264: .P2
        !           265: prints 1.
        !           266: .PP
        !           267: All variables that have never been set have the value
        !           268: .CW () .
        !           269: ......
        !           270: .NH
        !           271: Arguments
        !           272: .PP
        !           273: When
        !           274: .I rc
        !           275: is reading its input from a file, the file has access
        !           276: to the arguments supplied on
        !           277: .I rc 's
        !           278: command line.  The variable
        !           279: .CW $*
        !           280: initially has the list of arguments assigned to it.
        !           281: The names
        !           282: .CW $1 ,
        !           283: .CW $2 ,
        !           284: etc. are synonyms for
        !           285: .CW $*(1) ,
        !           286: .CW $*(2) ,
        !           287: etc.
        !           288: In addition,
        !           289: .CW $0
        !           290: is the name of the file from which
        !           291: .I rc 's
        !           292: input is being read.
        !           293: .PP
        !           294: The built-in
        !           295: .CW shift
        !           296: command deletes the first member of
        !           297: .CW $* .
        !           298: If
        !           299: .CW shift
        !           300: is given an argument, it deletes the given
        !           301: number of members from
        !           302: .CW $*.
        !           303: Thus,
        !           304: .P1
        !           305: *=(Never, ever type rm -fr /)
        !           306: shift 2
        !           307: echo Please $*
        !           308: .P2
        !           309: would print
        !           310: .P1
        !           311: Please type rm -fr /
        !           312: .P2
        !           313: .NH
        !           314: Concatenation
        !           315: .PP
        !           316: .I Rc
        !           317: has a string concatenation operator, the caret 
        !           318: .CW ^ ,
        !           319: to build a arguments out of pieces.
        !           320: .P1
        !           321: echo hully^gully
        !           322: .P2
        !           323: is exactly equivalent to
        !           324: .P1
        !           325: echo hullygully
        !           326: .P2
        !           327: Suppose variable
        !           328: .CW i
        !           329: contains the name of a command.
        !           330: Then
        !           331: .P1
        !           332: cc -o $i $i^.c
        !           333: .P2
        !           334: might compile the command's source code, leaving the
        !           335: result in the appropriate file.
        !           336: .PP
        !           337: Concatenation distributes over lists. The following
        !           338: .P1
        !           339: echo (a b c)^(1 2 3)
        !           340: src=(main subr io)
        !           341: cc $src^.c
        !           342: .P2
        !           343: are equivalent to
        !           344: .P1
        !           345: echo a1 b2 c3
        !           346: cc main.c subr.c io.c
        !           347: .P2
        !           348: In detail, the rule is: if both operands of
        !           349: .CW ^
        !           350: are lists of the same non-zero number of strings, they are concatenated
        !           351: pairwise.  Otherwise, if one of the operands is a single string,
        !           352: it is concatenated with each member of the other operand in turn.
        !           353: Any other combination of operands is an error.
        !           354: .NH
        !           355: Free carets
        !           356: .PP
        !           357: User demand has dictated that
        !           358: .I rc
        !           359: insert carets in certain places, to make the syntax
        !           360: look more like the Bourne shell.  For example, this:
        !           361: .P1
        !           362: cc -$flags $stems.c
        !           363: .P2
        !           364: is equivalent to
        !           365: .P1
        !           366: cc -^$flags $stems^.c
        !           367: .P2
        !           368: In general,
        !           369: .I rc
        !           370: will insert
        !           371: .CW ^
        !           372: between two arguments that are not separated by white space.
        !           373: Specifically, whenever one of
        !           374: .CW "$'`
        !           375: follows a quoted or unquoted word, or an unquoted word follows
        !           376: a quoted word with no intervening blanks or tabs, a
        !           377: .CW ^
        !           378: is inserted between the two.  If an unquoted word immediately following a
        !           379: .CW $
        !           380: contains a character other than an alphanumeric, underscore or
        !           381: .CW * ,
        !           382: a
        !           383: .CW ^
        !           384: is inserted before the first such character.
        !           385: .NH
        !           386: Command substitution
        !           387: .PP
        !           388: It is often useful to build an argument list from the output of a command.
        !           389: .I Rc
        !           390: allows a command, enclosed in braces and preceded by a left quote,
        !           391: .CW "`{...}" ,
        !           392: anywhere that an argument is required.  The command is executed and its
        !           393: standard output captured.
        !           394: The characters stored in the variable
        !           395: .CW ifs
        !           396: are used to split the output into arguments.
        !           397: For example,
        !           398: .P1
        !           399: cat `{ls -tr|sed 10q}
        !           400: .P2
        !           401: will catenate the ten oldest files in the current directory in temporal order.
        !           402: .NH
        !           403: Pipeline branching
        !           404: .PP
        !           405: The pipeline notation described above is general enough for almost all cases.
        !           406: Very occasionally it is useful to have pipelines that are not linear.
        !           407: Pipeline topologies more general than trees can require arbitrarily large pipe buffers,
        !           408: or worse, can cause deadlock.
        !           409: .I Rc
        !           410: has syntax for some kinds of non-linear but treelike pipelines.
        !           411: For example,
        !           412: .P1
        !           413:        cmp <{old} <{new}
        !           414: .P2
        !           415: will regression test a new version of a command.
        !           416: A
        !           417: .CW <
        !           418: (or
        !           419: .CW > )
        !           420: followed by a command in braces causes the command to be run with
        !           421: its standard output (or input) attached to a pipe.  The parent command
        !           422: .CW cmp "" (
        !           423: in the example)
        !           424: is started with the other end of the pipe attached to some file descriptor
        !           425: or other, and with an argument that will connect to the pipe when opened
        !           426: (e.g.
        !           427: .CW /dev/fd/6 .)
        !           428: On systems without
        !           429: .CW /dev/fd ,
        !           430: or something similar (SunOS for example) this feature does not work.
        !           431: .....
        !           432: .NH
        !           433: Exit status
        !           434: .PP
        !           435: When a command exits, it returns status to the program that executed it.
        !           436: On UNIX, status is a small positive number, with zero indicating normal termination
        !           437: and non-zero values encoding error conditions (in a non-standard way).  If a
        !           438: UNIX command terminates abnormally rather than by executing
        !           439: .CW exit (2),
        !           440: .I rc
        !           441: takes the status to be 1000 plus the termination status provided to
        !           442: .CW wait (2).
        !           443: On Plan 9 status is a character string describing an error condition.
        !           444: On normal termination it is empty.
        !           445: .PP
        !           446: .I Rc
        !           447: captures commands' exit statuses in the variable
        !           448: .CW $status .
        !           449: For a simple command, the value of
        !           450: .CW $status
        !           451: is just as described above.  For a pipeline,
        !           452: .CW $status
        !           453: is set to the concatenation of the statuses of the pipeline components,
        !           454: with
        !           455: .CW |
        !           456: characters for separators.
        !           457: .PP
        !           458: .I Rc
        !           459: has a number of command forms that various kinds of control flow,
        !           460: many of them conditioned by the status returned from previously
        !           461: executed commands.  In all cases, any
        !           462: .CW $status
        !           463: containing only
        !           464: .CW 0 's
        !           465: and
        !           466: .CW | 's
        !           467: has boolean value
        !           468: .I true .
        !           469: Any other status is
        !           470: .I false .
        !           471: .NH
        !           472: Flow of control
        !           473: .PP
        !           474: .I Rc
        !           475: will accept multiple commands on a line, separated by
        !           476: .CW &
        !           477: or
        !           478: .CW ; .
        !           479: A command followed by
        !           480: .CW &
        !           481: is executed asynchronously \(em
        !           482: .I rc
        !           483: does not wait for it to exit, and it
        !           484: disconnects its standard input from the terminal,
        !           485: redirecting it to
        !           486: .CW /dev/null
        !           487: so that the command and
        !           488: .I rc
        !           489: do not compete for input lines.
        !           490: The process id of an asynchronous command is stored in the variable
        !           491: .CW $apid ,
        !           492: and if
        !           493: .I rc
        !           494: is running interactively (that is, its input is coming from a terminal),
        !           495: the process id is printed when the command starts.
        !           496: .PP
        !           497: Commands separated by
        !           498: .CW ;
        !           499: are executed in sequence, but
        !           500: .I rc
        !           501: waits for the first command to terminate before starting the second.
        !           502: Thus
        !           503: .P1
        !           504: fortune;fortune&
        !           505: .P2
        !           506: prints out two fortunes (and a process id), not waiting for the
        !           507: second to appear before prompting for more commands.
        !           508: .NH
        !           509: Command grouping
        !           510: .PP
        !           511: A sequence of commands enclosed in
        !           512: .CW {}
        !           513: may be used anywhere a command is required.
        !           514: For example:
        !           515: .P1
        !           516: {sleep 3600;echo 'Time''s up!'}&
        !           517: .P2
        !           518: will wait an hour in the background, then print a message.
        !           519: Without the braces:
        !           520: .P1
        !           521: sleep 3600;echo 'Time''s up!'&
        !           522: .P2
        !           523: this would lock up the terminal for an hour,
        !           524: then print the message in the background!
        !           525: .NH
        !           526: Conditional execution \(em \f(CW&&\fP and \f(CW||\fP
        !           527: .PP
        !           528: A pair of commands may be separated by
        !           529: .CW &&
        !           530: or
        !           531: .CW || .
        !           532: In either case, the first command is executed and its
        !           533: status examined.
        !           534: If the operator is
        !           535: .CW &&
        !           536: and the status is
        !           537: .I true ,
        !           538: the second command is executed.
        !           539: If the operator is
        !           540: .CW ||
        !           541: the status must be
        !           542: .I false
        !           543: to execute the second command.
        !           544: Thus
        !           545: .P1
        !           546: cyntax *.c && cc -g -o cmd *.c
        !           547: .P2
        !           548: compiles
        !           549: .CW cmd
        !           550: only if
        !           551: .CW cyntax
        !           552: passes on it, and
        !           553: .P1
        !           554: {sleep 86400;rm -r /junk} ||
        !           555:     echo Failure!|mail td &
        !           556: .P2
        !           557: waits 24 hours, then tries to remove all files in
        !           558: .CW /junk .
        !           559: On failure it sends me mail.  It does all of this in
        !           560: the background, so I can use my terminal for something
        !           561: else in the interim.
        !           562: .NH
        !           563: Subshells
        !           564: .PP
        !           565: The
        !           566: .CW @
        !           567: operator executes the following command in a new process.
        !           568: This is useful primarily to insulate the parent process
        !           569: from the effects of built-in commands, like this
        !           570: .P1
        !           571: @ {cd /elsewhere;tar cf - .} |
        !           572:     tar -xf -
        !           573: .P2
        !           574: This dubious but venerated idiom copies
        !           575: the contents of
        !           576: .CW /elsewhere
        !           577: to the current directory by building a
        !           578: .CW tar
        !           579: file on standard output and immediately
        !           580: cracking it at the other end of a pipe.
        !           581: The first
        !           582: .CW tar
        !           583: runs in
        !           584: .CW /elsewhere ,
        !           585: but, because of the
        !           586: .CW @ ,
        !           587: the second operates in the original directory.
        !           588: .NH
        !           589: Control flow \(em \f(CWfor\fP
        !           590: .PP
        !           591: A command may be executed once for each member of a list
        !           592: by typing, for example:
        !           593: .P1
        !           594: for(i in printf scanf putchar)
        !           595:     look $i /usr/td/lib/dw.dat
        !           596: .P2
        !           597: This looks for each of the words
        !           598: .CW printf ,
        !           599: .CW scanf
        !           600: and
        !           601: .CW putchar
        !           602: in the given file.
        !           603: The general form is
        !           604: .P1
        !           605: for(\fIname\fP in \fIlist\fP)
        !           606:     \fIcommand\fP
        !           607: .P2
        !           608: or
        !           609: .P1
        !           610: for(\fIname\fP)
        !           611:     \fIcommand\fP
        !           612: .P2
        !           613: In the first case,
        !           614: .I command
        !           615: is executed once for each member of
        !           616: .I list ,
        !           617: with that member assigned to variable
        !           618: .I name .
        !           619: If
        !           620: .CI in " list
        !           621: is not given,
        !           622: .I $*
        !           623: is used.
        !           624: .NH
        !           625: Conditional execution \(em \f(CWif\fP
        !           626: .PP
        !           627: .I Rc
        !           628: also provides a general if-statement.  For example:
        !           629: .P1
        !           630: if(cyntax *.c)
        !           631:     cc -g -o cmd *.c
        !           632: .P2
        !           633: is equivalent to the similar example above.
        !           634: An `if not' statement provides a two-tailed conditional.
        !           635: For example:
        !           636: .P1
        !           637: for(i){
        !           638:     if(test -f /tmp/$i)
        !           639:         echo $i already in /tmp
        !           640:     if not
        !           641:         cp $i /tmp
        !           642: }
        !           643: .P2
        !           644: This loops over each file in
        !           645: .CW $* ,
        !           646: copying to
        !           647: .CW /tmp
        !           648: those that do not already appear there, and
        !           649: printing a message for those that do.
        !           650: .NH
        !           651: Control flow \(em \f(CWwhile\fP
        !           652: .PP
        !           653: .I Rc 's
        !           654: while statement looks like this:
        !           655: .P1
        !           656: while(newer subr.c subr.o) sleep 5
        !           657: .P2
        !           658: This waits until
        !           659: .CW subr.o
        !           660: is newer than
        !           661: .CW subr.c
        !           662: (presumably because the C compiler finished with it.)
        !           663: .NH
        !           664: Control flow \(em \f(CWswitch\fP
        !           665: .PP
        !           666: .I Rc
        !           667: provides a switch statement to do pattern-matching on
        !           668: arbitrary strings.  Its general form is
        !           669: .P1
        !           670: switch(\fIword\fP){
        !           671: case \fIpattern ...\fP
        !           672:     \fIcommands\fP
        !           673: case \fIpattern ...\fP
        !           674:     \fIcommands\fP
        !           675: ...
        !           676: }
        !           677: .P2
        !           678: .I Rc
        !           679: attempts to match the word against the patterns in each case statement in turn.
        !           680: Patterns are the same as for filename matching, except that
        !           681: .CW /
        !           682: and the first characters of
        !           683: .CW .
        !           684: and
        !           685: .CW ..
        !           686: need not be matched explicitly.
        !           687: .PP
        !           688: If any pattern matches, the
        !           689: commands following that case up to
        !           690: the next case (or the end of the switch)
        !           691: are executed, and execution of the switch
        !           692: is complete.  For example,
        !           693: .P1
        !           694: switch($#*){
        !           695: case 1
        !           696:     cat >>$1
        !           697: case 2
        !           698:     cat >>$2 <$1
        !           699: case *
        !           700:     echo 'Usage: append [from] to'
        !           701: }
        !           702: .P2
        !           703: is an append command.  Called with one file argument,
        !           704: it tacks standard input to its end.  With two, the
        !           705: first is appended to the second.  Any other number
        !           706: elicits a usage message.
        !           707: .PP
        !           708: The built-in
        !           709: .CW ~
        !           710: command also matches patterns, and is often more concise than a switch.
        !           711: Its arguments are a string and a list of patterns.  It sets
        !           712: .CW $status
        !           713: to zero if and only if any of the patterns matches the string.
        !           714: The following example processes option arguments for the
        !           715: .I man (1)
        !           716: command:
        !           717: .P1
        !           718: opt=()
        !           719: while(~ $1 -* [1-9] 10){
        !           720:     switch($1){
        !           721:     case [1-9] 10
        !           722:         sec=$1 secn=$1
        !           723:     case -f
        !           724:         c=f s=f
        !           725:     case -[qwnt]
        !           726:         cmd=$1
        !           727:     case -T*
        !           728:         T=$1
        !           729:     case -*
        !           730:         opt=($opt $1)
        !           731:     }
        !           732:     shift
        !           733: }
        !           734: .P2
        !           735: .NH
        !           736: Functions
        !           737: .PP
        !           738: Functions may be defined by typing
        !           739: .P1
        !           740: fn \fIname\fP { \fIcommands\fP }
        !           741: .P2
        !           742: Subsequently, whenever a command named
        !           743: .I name
        !           744: is encountered, the remainder of the command's
        !           745: argument list will assigned to
        !           746: .CW $*
        !           747: and
        !           748: .I rc
        !           749: will execute the
        !           750: .I commands .
        !           751: The value of
        !           752: .CW $*
        !           753: will be restored on completion.
        !           754: For example:
        !           755: .P1
        !           756: fn g {
        !           757:     gre -e $1 *.[hcyl]
        !           758: }
        !           759: .P2
        !           760: defines
        !           761: .CI g " pattern
        !           762: to look for occurrences of
        !           763: .I pattern
        !           764: in all program source files in the current directory.
        !           765: .PP
        !           766: Function definitions are deleted by writing
        !           767: .P1
        !           768: fn \fIname\fP
        !           769: .P2
        !           770: with no function body.
        !           771: .....
        !           772: .NH
        !           773: Command execution
        !           774: .PP
        !           775: Up to now we've said very little about what
        !           776: .I rc
        !           777: does to execute a simple command.
        !           778: If the command name is the name of a function defined using
        !           779: .CW fn ,
        !           780: the function is executed.
        !           781: Otherwise, if it is the name of a built-in command, the
        !           782: built-in is executed directly by
        !           783: .I rc .
        !           784: Otherwise, if the name contains a
        !           785: .CW / ,
        !           786: it is taken to be the name of a binary program
        !           787: and is executed using
        !           788: .I exec (2).
        !           789: If the name contains no
        !           790: .CW / ,
        !           791: then directories mentioned in the variable
        !           792: .CW $path
        !           793: are searched until an executable file is found.
        !           794: .NH
        !           795: Built-in commands
        !           796: .PP
        !           797: Several commands are executed internally by
        !           798: .I rc ,
        !           799: usually because their execution changes or depends on
        !           800: .I rc 's
        !           801: internal state.
        !           802: .TP ". [-i] \fIfile ...\fT
        !           803: Execute commands from
        !           804: .I file .
        !           805: .CW $*
        !           806: is set for the duration to the reminder of the argument list following
        !           807: .I file .
        !           808: .CW $path
        !           809: is used to search for
        !           810: .I file .
        !           811: Option
        !           812: .CW -i
        !           813: indicates interactive input \(mi a prompt
        !           814: (found in
        !           815: .CW $prompt )
        !           816: is printed before each command is read.
        !           817: .TP "builtin \fIcommand ...\fT
        !           818: Execute
        !           819: .I command
        !           820: as usual except that any function named
        !           821: .I command
        !           822: is ignored.
        !           823: For example,
        !           824: .P1
        !           825: fn cd{
        !           826:     builtin cd $* && pwd
        !           827: }
        !           828: .P2
        !           829: defines a replacement for the
        !           830: .CW cd
        !           831: built-in (see below) that announces the full name of the new directory.
        !           832: .TP "cd [\fIdir\fT]
        !           833: Change the current directory to
        !           834: .I dir .
        !           835: The default argument is
        !           836: .CW $home .
        !           837: .CW $cdpath
        !           838: is a list of places in which to search for
        !           839: .I dir .
        !           840: .TP "eval [\fIarg ...\fT]
        !           841: The arguments are concatenated separated by spaces into a string, read as input to
        !           842: .I rc ,
        !           843: and executed.  For example,
        !           844: .P1
        !           845: x='$y'
        !           846: y=Doody
        !           847: eval echo Howdy, $x
        !           848: .P2
        !           849: would echo
        !           850: .P1
        !           851: Howdy, Doody
        !           852: .P2
        !           853: since arguments of
        !           854: .CW eval
        !           855: would be
        !           856: .P1
        !           857: Howdy, $y
        !           858: .P2
        !           859: .TP "exec \fIcommand ...\fT
        !           860: .I Rc
        !           861: replaces itself with the given non-built-in
        !           862: .I command .
        !           863: .TP "exit [\fIstatus\fP]
        !           864: Exit with the given status.  If none is given, the current value of
        !           865: .CW $status
        !           866: is used.
        !           867: .TP finit
        !           868: Initialize functions imported from the environment.
        !           869: Intended for use only by
        !           870: .I rc 's
        !           871: initialization procedure.
        !           872: Currently this is non-functional on Plan 9, as no
        !           873: means of environmental function-storage yet exists.
        !           874: .TP "flag \fIletter\fP"
        !           875: Sets
        !           876: .CW $status
        !           877: to zero if and only if
        !           878: .I rc
        !           879: was invoked with option
        !           880: .CI - letter
        !           881: set.  Intended for use by
        !           882: .I rc 's
        !           883: initialization procedure.
        !           884: .TP "mount \fInew old\fT
        !           885: (Plan 9 only.)
        !           886: Mount the name
        !           887: .I new
        !           888: on
        !           889: .I old .
        !           890: .TP "shift [\fIn\fT]
        !           891: Delete the first
        !           892: .I n
        !           893: (default 1) elements of
        !           894: .CW $* .
        !           895: .TP "umask [\fIoctal\fP]
        !           896: (UNIX only.)  Set
        !           897: .I rc 's
        !           898: file creation mask to the given octal value.
        !           899: If no value is given, the current mask value is printed.
        !           900: .TP "unmount [\fInew\fT] \fIold
        !           901: (Plan 9 only.)
        !           902: Unmount the name
        !           903: .I old .
        !           904: If
        !           905: .I new
        !           906: is given, unmount
        !           907: .I old
        !           908: from
        !           909: .I new .
        !           910: .TP "wait [\fIpid\fP]
        !           911: Wait for the process with the given
        !           912: .I pid
        !           913: to exit.  If no
        !           914: .I pid
        !           915: is given, all outstanding processes are waited for.
        !           916: .TP "whatis \fIname ...\fT
        !           917: Print the value of each
        !           918: .I name
        !           919: in a form suitable for input to
        !           920: .I rc .
        !           921: The output is an assignment to any variable, the definition of any function,
        !           922: a call to
        !           923: .CW builtin
        !           924: for any built-in command, or the full path name of any binary program.
        !           925: For example,
        !           926: .P1
        !           927: whatis path g cd who
        !           928: .P2
        !           929: might print
        !           930: .P1
        !           931: path=(. /bin /usr/bin)
        !           932: fn g {gre -e $1 *.[hycl]}
        !           933: builtin cd
        !           934: /bin/who
        !           935: .P2
        !           936: .TP "~ \fIsubject pattern ...
        !           937: The
        !           938: .I subject
        !           939: is matched against each
        !           940: .I pattern
        !           941: in turn.  On a match,
        !           942: .CW $status
        !           943: is set to zero.
        !           944: Otherwise, it is set to one.
        !           945: Patterns are the same as for filename matching,
        !           946: except that
        !           947: .CW /
        !           948: and the first character of
        !           949: .CW .
        !           950: and
        !           951: .CW ..
        !           952: need not be matched explicitly.
        !           953: The
        !           954: .I patterns
        !           955: are not subjected to filename replacement before the
        !           956: .CW ~
        !           957: command is executed, so they need not be enclosed in
        !           958: quotation marks, unless of course, a literal match for
        !           959: .CW *
        !           960: .CW [
        !           961: or
        !           962: .CW ?
        !           963: is required.
        !           964: For example
        !           965: .P1
        !           966: ~ $1 ?
        !           967: .P2
        !           968: matches any single character, whereas
        !           969: .P1
        !           970: ~ $1 '?'
        !           971: .P2
        !           972: only matches a literal question mark.
        !           973: .NH
        !           974: Special variables
        !           975: .PP
        !           976: Several variables are set internally by
        !           977: .I rc
        !           978: or used to guide its execution.
        !           979: .TP $*
        !           980: Set to
        !           981: .I rc 's
        !           982: argument list during initialization.
        !           983: A
        !           984: .CW .
        !           985: command or function execution saves
        !           986: .CW $*
        !           987: on a stack and sets it to the new argument list.  The saved
        !           988: value is restored on completion.
        !           989: .TP $apid
        !           990: Whenever a process is started asynchronously with
        !           991: .CW & ,
        !           992: .CW $apid
        !           993: receives its process id.
        !           994: .TP $cflag
        !           995: Set to the string provided on
        !           996: .I rc 's
        !           997: command line with the
        !           998: .CW -c
        !           999: option, if any.  This is provided for the
        !          1000: use of
        !          1001: .I rc's initialization procedure.
        !          1002: .TP $home
        !          1003: The default directory for
        !          1004: .CW cd .
        !          1005: On UNIX, if
        !          1006: .CW $home
        !          1007: is not initially set, and
        !          1008: .CW $HOME
        !          1009: is, then
        !          1010: .CW $home
        !          1011: is set to
        !          1012: .CW $HOME .
        !          1013: .TP $ifs
        !          1014: The input field separators used in command substitution.
        !          1015: If not set in
        !          1016: .I rc 's
        !          1017: environment, it is initialized to blank, tab and newline.
        !          1018: .TP $path
        !          1019: The search path used to find commands and input files for the
        !          1020: .CW .
        !          1021: command.
        !          1022: If not set in the environment, it is initialized to
        !          1023: .CW "(. /bin /usr/bin)
        !          1024: on UNIX,
        !          1025: .CW "(. /bin)
        !          1026: on Plan 9.
        !          1027: .TP $pid
        !          1028: Set during initialization to
        !          1029: .I rc 's
        !          1030: process id.
        !          1031: .TP $prompt
        !          1032: When
        !          1033: .I rc
        !          1034: is run interactively, the first member of
        !          1035: .CW $prompt
        !          1036: is printed before reading each command.
        !          1037: The second member is printed if
        !          1038: .I rc
        !          1039: expects a command to be continued on another line.
        !          1040: If not set in the environment,
        !          1041: .I rc
        !          1042: initializes it to
        !          1043: .CW "('% ' '   ')" .
        !          1044: .TP $status
        !          1045: On UNIX, this is set to the low 8 bits of the
        !          1046: .I exit (2)
        !          1047: argument of a normally terminating binary (unless started with
        !          1048: .CW & ),
        !          1049: or to 1000 plus the termination status on abnormal termination.
        !          1050: On Plan 9,
        !          1051: .CW $status
        !          1052: is set to the process's termination message.
        !          1053: On either system, the statuses of all processes in a pipeline
        !          1054: are captured and concatenated, separated by
        !          1055: .CW |
        !          1056: characters.
        !          1057: .CW !
        !          1058: and
        !          1059: .CW ~
        !          1060: also set
        !          1061: .CW $status .
        !          1062: Its value is used to control execution in
        !          1063: .CW && ,
        !          1064: .CW || ,
        !          1065: .CW if
        !          1066: and
        !          1067: .CW while
        !          1068: commands.
        !          1069: When
        !          1070: .I rc
        !          1071: exits at end-of-file of its input or on executing an
        !          1072: .CW exit
        !          1073: command with no argument,
        !          1074: .CW $status
        !          1075: is its exit status.
        !          1076: (This is only strictly true on Plan 9.  On UNIX, the exit status
        !          1077: must be numeric.  Therefore, if the value of
        !          1078: .CW $status
        !          1079: contains
        !          1080: .CW |
        !          1081: characters, they are deleted before converting it to a number, and if
        !          1082: .CW $status
        !          1083: contains other non-numeric characters,
        !          1084: .I rc
        !          1085: exits with status 1.)
        !          1086: .NH
        !          1087: Advanced I/O Redirection
        !          1088: .PP
        !          1089: .I Rc
        !          1090: allows redirection of file descriptors other than 0 and 1
        !          1091: (standard input and output) by specifying the file descriptor
        !          1092: in square brackets
        !          1093: .CW "[ ]
        !          1094: after the
        !          1095: .CW <
        !          1096: or
        !          1097: .CW > .
        !          1098: For example,
        !          1099: .P1
        !          1100: cc junk.c >[2]junk.diag
        !          1101: .P2
        !          1102: saves the compiler's diagnostics in
        !          1103: .CW junk.diag .
        !          1104: .PP
        !          1105: File descriptors may be replaced by a copy, in the sense of
        !          1106: .I dup (2),
        !          1107: of an already-open file by typing, for example
        !          1108: .P1
        !          1109: cc junk.c >[2=1]
        !          1110: .P2
        !          1111: This replaces file descriptor 2 with a copy of file descriptor 1.
        !          1112: It is more useful in conjunction with other redirections, like this
        !          1113: .P1
        !          1114: cc junk.c >junk.out >[2=1]
        !          1115: .P2
        !          1116: Redirections are evaluated from left to right, so this redirects
        !          1117: file descriptor 1 to
        !          1118: .CW junk.out ,
        !          1119: then points file descriptor 2 at the same file.
        !          1120: By contrast,
        !          1121: .P1
        !          1122: cc junk.c >[2=1] >junk.out
        !          1123: .P2
        !          1124: Redirects file descriptor 2 to a copy of file descriptor 1
        !          1125: (presumably the terminal), and then directs file descriptor 1
        !          1126: at a file.  In the first case, standard and diagnostic output
        !          1127: will be intermixed in
        !          1128: .CW junk.out .
        !          1129: In the second, diagnostic output will appear on the terminal,
        !          1130: and standard output will be sent to the file.
        !          1131: .PP
        !          1132: File descriptors may be closed by using the duplication notation
        !          1133: with an empty right-hand side.
        !          1134: For example,
        !          1135: .P1
        !          1136: cc junk.c >[2=]
        !          1137: .P2
        !          1138: will discard diagnostics from the compilation.
        !          1139: Often closing a file descriptor will not have the
        !          1140: expected effect, because many UNIX programs do not
        !          1141: behave politely when started with file descriptors
        !          1142: 0, 1 or 2 closed.  Consider, for example,
        !          1143: .P1
        !          1144: who | tee a b c >[1=]
        !          1145: .P2
        !          1146: One might expect this to produce copies of the output of
        !          1147: .CW who
        !          1148: on files
        !          1149: .CW a ,
        !          1150: .CW b
        !          1151: and
        !          1152: .CW c ,
        !          1153: discarding the copy that
        !          1154: .CW tee
        !          1155: normally writes on its standard output.
        !          1156: However,
        !          1157: .CW tee
        !          1158: does not check for its standard output being closed.
        !          1159: When it opens
        !          1160: .CW a ,
        !          1161: the file descriptor returned is 1, and unsurprisingly,
        !          1162: .CW tee
        !          1163: writes two interleaved copies of its input onto
        !          1164: .CW a .
        !          1165: It is better explicitly to direct the output at
        !          1166: .CW /dev/null .
        !          1167: .PP
        !          1168: Arbitrary file descriptors may be sent through
        !          1169: a pipe by typing, for example
        !          1170: .P1
        !          1171: cc junk.c |[2] grep -v '^$'
        !          1172: .P2
        !          1173: This deletes those ever-so-annoying blank lines
        !          1174: from the C compiler's output.  Note that the output
        !          1175: of
        !          1176: .CW grep
        !          1177: still appears on file descriptor 1.
        !          1178: .PP
        !          1179: Very occasionally you may wish to connect the input side of
        !          1180: a pipe to some file descriptor other than zero.
        !          1181: The notation
        !          1182: .P1
        !          1183: cmd1 |[5=19] cmd2
        !          1184: .P2
        !          1185: creates a pipeline with
        !          1186: .CW cmd1 's
        !          1187: file descriptor 5 connected through a pipe to
        !          1188: .CW cmd2 's
        !          1189: file descriptor 19.
        !          1190: .NH
        !          1191: Here documents
        !          1192: .PP
        !          1193: .I Rc
        !          1194: procedures may include data, called ``here documents'',
        !          1195: to be provided as input to commands, as in this version of the
        !          1196: .I tel
        !          1197: command
        !          1198: .P1
        !          1199: for(i) grep $i <<!
        !          1200: ...
        !          1201: nls 2T-402 2912
        !          1202: norman 2C-514 2842
        !          1203: pjw 2T-502 7214
        !          1204: ...
        !          1205: !
        !          1206: .P2
        !          1207: A here document is introduced by the redirection symbol
        !          1208: .CW << ,
        !          1209: followed by an arbitrary eof marker
        !          1210: .CW ! "" (
        !          1211: in the example).  Lines following the command,
        !          1212: up to a line containing only the eof marker are saved
        !          1213: in a temporary file that it connected to the command's
        !          1214: standard input when it is run.
        !          1215: .PP
        !          1216: .I Rc
        !          1217: does variable substitution in here documents.  The following
        !          1218: .I subst
        !          1219: command:
        !          1220: .P1
        !          1221: ed $3 <<EOF
        !          1222: g/$1/s//$2/g
        !          1223: w
        !          1224: EOF
        !          1225: .P2
        !          1226: changes all occurrences of
        !          1227: .CW $1
        !          1228: to
        !          1229: .CW $2
        !          1230: in file
        !          1231: .CW $3 .
        !          1232: To include a literal
        !          1233: .CW $
        !          1234: in a here document, type
        !          1235: .CW $$ .
        !          1236: If the name of a variable is followed immediately by
        !          1237: .CW ^ ,
        !          1238: the caret is deleted.
        !          1239: .PP
        !          1240: Variable substitution can be entirely suppressed by enclosing
        !          1241: the eof marker following
        !          1242: .CW <<
        !          1243: in quotation marks.
        !          1244: .PP
        !          1245: Here documents may be provided on file descriptors other than 0 by typing, for example
        !          1246: .P1
        !          1247: cmd <<[4]End
        !          1248: ...
        !          1249: End
        !          1250: .P2
        !          1251: .NH
        !          1252: Signals
        !          1253: .PP
        !          1254: .I Rc
        !          1255: scripts normally terminate when an interrupt is received from the terminal.
        !          1256: A function with the name of a signal, in lower case, is defined in the usual way,
        !          1257: but called when
        !          1258: .I rc
        !          1259: receives the signal.  Signals of interest are:
        !          1260: .TP sighup
        !          1261: Hangup.  The controlling teletype has disconnected from
        !          1262: .I rc .
        !          1263: .TP sigint
        !          1264: The interrupt character (usually ASCII del) was typed on the controlling terminal.
        !          1265: .TP sigquit
        !          1266: The quit character (usually ASCII fs, ctrl-\e) was typed on the controlling terminal.
        !          1267: .TP sigterm
        !          1268: This signal is normally sent by
        !          1269: .I kill (1).
        !          1270: .TP sigexit
        !          1271: An artificial signal sent when
        !          1272: .I rc
        !          1273: is about to exit.
        !          1274: .LP
        !          1275: As an example,
        !          1276: .P1
        !          1277: fn sigint{
        !          1278:     rm /tmp/junk
        !          1279:     exit
        !          1280: }
        !          1281: .P2
        !          1282: sets a trap for the keyboard interrupt that
        !          1283: removes a temporary file before exiting.
        !          1284: .PP
        !          1285: Signals will be ignored if the signal routine is set to
        !          1286: .CW {} .
        !          1287: Signals revert to their default behavior when their handlers'
        !          1288: definitions are deleted.
        !          1289: .NH
        !          1290: Environment
        !          1291: .PP
        !          1292: The environment is a list of name-value pairs made available to
        !          1293: executing binaries.  On UNIX the environment is passed
        !          1294: to commands as a second argument list containing
        !          1295: an entry for each variable whose value is non-empty, and
        !          1296: an entry for each function.  UNIX does not directly support
        !          1297: environment entries containing multiple strings, so if a variable
        !          1298: has more than one component, these are separated by ctrl-a
        !          1299: .CW \e001 ) (
        !          1300: characters.
        !          1301: .PP
        !          1302: On Plan 9, the environment is stored in a file system named
        !          1303: .CW #e ,
        !          1304: normally mounted on
        !          1305: .CW /env .
        !          1306: The value of each variable is stored in a separate file, with components
        !          1307: terminated by ASCII nuls.
        !          1308: (This is not quite as horrendous as it sounds, the file system is
        !          1309: maintained entirely in core, so no disk or network access is involved.)
        !          1310: The contents of
        !          1311: .CW /env
        !          1312: are shared on a per-process group basis \(mi when a new process group is
        !          1313: created it effectively attaches
        !          1314: .CW /env
        !          1315: to a new file system initialized with a copy of the old one.
        !          1316: A consequence of this organization is that commands can change environment
        !          1317: entries and see the changes reflected in
        !          1318: .I rc .
        !          1319: This is not possible on UNIX, as the environment is passed to children by
        !          1320: .I exec (2),
        !          1321: but is not passed back by
        !          1322: .I fork (2)
        !          1323: and
        !          1324: .I wait (2).
        !          1325: .PP
        !          1326: There is not currently a way on Plan 9 to place functions in the environment,
        !          1327: although this could easily done by mounting another instance of
        !          1328: .CW #e
        !          1329: on another directory.  The problem is that currently there can be only one instance of
        !          1330: .CW #e
        !          1331: per process group.
        !          1332: .NH
        !          1333: Local Variables
        !          1334: .PP
        !          1335: It is often useful to set a variable for the duration
        !          1336: of a single command.  An assignment followed by a command
        !          1337: has this effect.  For example
        !          1338: .P1
        !          1339: a=global
        !          1340: a=local echo $a
        !          1341: echo $a
        !          1342: .P2
        !          1343: will print
        !          1344: .P1
        !          1345: local
        !          1346: global
        !          1347: .P2
        !          1348: This works even for compound commands, like
        !          1349: .P1
        !          1350: f=/fairly/long/file/name {
        !          1351:     {   wc $f
        !          1352:         spell $f
        !          1353:         diff $f.old $f
        !          1354:     } | pr -h 'Facts about '$f |
        !          1355:         lp -ddp
        !          1356: }
        !          1357: .P2
        !          1358: .NH
        !          1359: Invocation
        !          1360: .PP
        !          1361: When
        !          1362: .I rc
        !          1363: starts, it digests its option arguments, initializes variables
        !          1364: and functions from the environment, sets
        !          1365: .CW $* ,
        !          1366: .CW $pid
        !          1367: and, if the
        !          1368: .CW -c
        !          1369: option is given,
        !          1370: .CW $cflag ,
        !          1371: and starts reading commands.
        !          1372: .PP
        !          1373: Most of
        !          1374: .I rc 's
        !          1375: initialization is done in a command file that is run at startup.
        !          1376: On UNIX the file is called
        !          1377: .CW /usr/lib/rcmain .
        !          1378: On Plan 9 it is
        !          1379: .CW /sys/lib/rcmain .
        !          1380: .LP
        !          1381: Legal options are:
        !          1382: .TP "-c \fIstring
        !          1383: Commands are read from
        !          1384: .I string .
        !          1385: .TP -e
        !          1386: Exit if
        !          1387: .CW $status
        !          1388: is non-zero after executing any simple command.
        !          1389: .TP -i
        !          1390: Interactive mode.
        !          1391: Also set if
        !          1392: .I rc
        !          1393: is given no arguments and its standard input is a terminal,
        !          1394: as determined by
        !          1395: .I isatty (3)
        !          1396: on UNIX, or by presumption on Plan 9.
        !          1397: Commands are prompted for using
        !          1398: .CW $prompt .
        !          1399: .CW SIGINT
        !          1400: and
        !          1401: .CW SIGQUIT
        !          1402: are caught and sloughed off.
        !          1403: .TP -I
        !          1404: Non-interactive mode.
        !          1405: Suppresses interactive mode even if
        !          1406: .I rc
        !          1407: is given no arguments and its standard input is a terminal.
        !          1408: .TP -l
        !          1409: Login mode.
        !          1410: Also set if the first character of argument zero is
        !          1411: .CW - 
        !          1412: (this is an obscure UNIX convention).
        !          1413: .I Rc
        !          1414: reads commands from
        !          1415: .CW $home/.rcrc ,
        !          1416: if it exists, before reading its normal input.
        !          1417: .TP -p
        !          1418: Protected mode.
        !          1419: .CW $path
        !          1420: is set to
        !          1421: .CW "(/bin /usr/bin)
        !          1422: on UNIX, or
        !          1423: .CW "/bin
        !          1424: on Plan 9, regardless of the setting in the environment.
        !          1425: Furthermore, functions are not initialized from the environment.
        !          1426: This provides a ``protected environment'' in which it is
        !          1427: difficult for malicious users to subvert an
        !          1428: .I rc
        !          1429: script by placing Trojan-horse versions of commands in
        !          1430: the environment or an unprotected directory.  On Plan 9 this is
        !          1431: not much use, since the meaning of all names, including those in
        !          1432: .CW /bin ,
        !          1433: is determined by the user.
        !          1434: .TP -v
        !          1435: Echo input on file descriptor 2 (diagnostic output) as it is read.
        !          1436: Useful for clarifying syntax problems in
        !          1437: .I rc
        !          1438: scripts.
        !          1439: .TP -x
        !          1440: Print each simple command on diagnostic output before executing it.
        !          1441: Useful for debugging
        !          1442: .I rc
        !          1443: scripts.
        !          1444: .PP
        !          1445: The following flags are useful primarily for debugging
        !          1446: .I rc .
        !          1447: .TP -d
        !          1448: Causes
        !          1449: .I rc
        !          1450: only to catch
        !          1451: .CW SIGINT ,
        !          1452: so that
        !          1453: .CW SIGQUIT
        !          1454: will cause it to dump core.
        !          1455: .TP -r
        !          1456: .I Rc 's
        !          1457: interpreter will print a running commentary on its state.
        !          1458: This is useful only for debugging
        !          1459: .I rc .
        !          1460: .TP -V
        !          1461: Echo input on diagnostic output as it is read, including
        !          1462: .CW rcmain ,
        !          1463: which is normally suppressed when using
        !          1464: .CW -v .
        !          1465: .NH
        !          1466: Examples \(em \fIcd, pwd\fP
        !          1467: .PP
        !          1468: Here is a pair of functions that provide
        !          1469: enhanced versions of the standard
        !          1470: .CW cd
        !          1471: and
        !          1472: .CW pwd
        !          1473: commands.  (Thanks to Rob Pike for these.)
        !          1474: .P1
        !          1475: ps1='% '       # default prompt
        !          1476: tab='  '       # a tab character
        !          1477: fn pbd{
        !          1478:   /bin/pwd|sed 's;.*/;;'
        !          1479: }
        !          1480: fn cd{
        !          1481:   builtin cd $1 &&
        !          1482:   switch($#*){
        !          1483:   case 0
        !          1484:     dir=$home
        !          1485:     prompt=($ps1 $tab)
        !          1486:   case *
        !          1487:     switch($1)
        !          1488:     case /*
        !          1489:       dir=$1
        !          1490:       prompt=(`{pbd}^$ps1 $tab)
        !          1491:     case */* ..*
        !          1492:       dir=()
        !          1493:       prompt=(`{pbd}^$ps1 $tab)
        !          1494:     case *
        !          1495:       dir=()
        !          1496:       prompt=($1^$ps1 $tab)
        !          1497:     }
        !          1498:   }
        !          1499: }
        !          1500: fn pwd{
        !          1501:   if(~ $#dir 0)
        !          1502:     dir=`{/bin/pwd}
        !          1503:   echo $dir
        !          1504: }
        !          1505: .P2
        !          1506: Function
        !          1507: .CW pwd
        !          1508: is a version of the standard
        !          1509: .CW pwd
        !          1510: that caches its value in variable
        !          1511: .CW $dir ,
        !          1512: because the genuine
        !          1513: .CW pwd
        !          1514: can be quite slow to execute.
        !          1515: .PP
        !          1516: Function
        !          1517: .CW pbd
        !          1518: is a helper that prints the last component of a directory name.
        !          1519: Function
        !          1520: .CW cd
        !          1521: calls the
        !          1522: .CW cd
        !          1523: built-in, and checks that it was successful.
        !          1524: If so, it sets
        !          1525: .CW $dir
        !          1526: and
        !          1527: .CW $prompt .
        !          1528: The prompt will include the last component of the
        !          1529: current directory (except in the home directory,
        !          1530: where it will be null), and
        !          1531: .CW $dir
        !          1532: will be reset either to the correct value or to
        !          1533: .CW () ,
        !          1534: so that the
        !          1535: .CW pwd
        !          1536: function will work correctly.
        !          1537: .NH
        !          1538: Examples \(em \fIman\fP
        !          1539: .PP
        !          1540: The
        !          1541: .I man
        !          1542: command prints pages from of the UNIX Programmer's Manual.
        !          1543: It is called, for example, as
        !          1544: .P1
        !          1545: man 3 isatty
        !          1546: man rc
        !          1547: man -t cat
        !          1548: .P2
        !          1549: In the first case, the page for
        !          1550: .I isatty
        !          1551: in section 3 is printed.
        !          1552: In the second case, the manual page for
        !          1553: .I rc
        !          1554: is printed.  Since no manual section is specified,
        !          1555: all sections are searched for the page, and it is found
        !          1556: in section 1.
        !          1557: In the third case, the page for
        !          1558: .I cat
        !          1559: is typeset (the
        !          1560: .CW -t
        !          1561: option).
        !          1562: .P1
        !          1563: cd /n/bowell/usr/man || {
        !          1564:   echo $0: Manual not on line! >[1=2]
        !          1565:   exit 1
        !          1566: }
        !          1567: NT=n  # default nroff
        !          1568: s='*' # section, default try all
        !          1569: for(i) switch($i){
        !          1570: case -t
        !          1571:   NT=t
        !          1572: case -n
        !          1573:   NT=n
        !          1574: case -*
        !          1575:   echo Usage: $0\e
        !          1576:     '[-nt] [section] page ...' >[1=2]
        !          1577:   exit 1
        !          1578: case [1-9] 10
        !          1579:   s=$i
        !          1580: case *
        !          1581:   eval 'pages=man'$s/$i'.*'
        !          1582:   for(page in $pages){
        !          1583:     if(test -f $page)
        !          1584:       $NT^roff -man $page
        !          1585:     if not
        !          1586:       echo $0: $i not found >[1=2]
        !          1587:   }
        !          1588: }
        !          1589: .P2
        !          1590: Note the use of
        !          1591: .CW eval
        !          1592: to make a list of candidate manual pages.
        !          1593: Without
        !          1594: .CW eval ,
        !          1595: the
        !          1596: .CW *
        !          1597: stored in
        !          1598: .CW $s
        !          1599: would not trigger filename matching
        !          1600: \(em it's enclosed in quotation marks,
        !          1601: and even if it weren't, it would be expanded
        !          1602: when assigned to
        !          1603: .CW $s .
        !          1604: Eval causes its arguments
        !          1605: to be re-processed by
        !          1606: .I rc 's
        !          1607: parser and interpreter, effectively delaying
        !          1608: evaluation of the
        !          1609: .CW *
        !          1610: until the assignment to
        !          1611: .CW $pages .
        !          1612: .NH
        !          1613: Examples \(em \fIholmdel\fP
        !          1614: .PP
        !          1615: The following
        !          1616: .I rc
        !          1617: script plays the deceptively simple game
        !          1618: .I holmdel ,
        !          1619: in which the players alternately name Bell Labs locations,
        !          1620: the winner being the first to mention Holmdel.
        !          1621: .KF
        !          1622: .P1
        !          1623: t=/tmp/holmdel$pid
        !          1624: fn read{
        !          1625:        $1=`{awk '{print;exit}'}
        !          1626: }
        !          1627: ifs='
        !          1628: \&'    # just a newline
        !          1629: fn sigexit sigint sigquit sighup{
        !          1630:        rm -f $t
        !          1631:        exit
        !          1632: }
        !          1633: cat <<'!' >$t
        !          1634: Allentown 
        !          1635: Atlanta
        !          1636: Cedar Crest
        !          1637: Chester
        !          1638: Columbus
        !          1639: Elmhurst
        !          1640: Fullerton
        !          1641: Holmdel
        !          1642: Indian Hill
        !          1643: Merrimack Valley
        !          1644: Morristown
        !          1645: Piscataway
        !          1646: Reading
        !          1647: Short Hills
        !          1648: South Plainfield
        !          1649: Summit
        !          1650: Whippany
        !          1651: West Long Branch
        !          1652: !
        !          1653: while(true){
        !          1654:    lab=`{/usr/games/fortune $t}
        !          1655:    echo $lab
        !          1656:    if(~ $lab Holmdel){
        !          1657:       echo You lose.
        !          1658:       exit
        !          1659:    }
        !          1660:    while(read lab
        !          1661:           ! grep -i -s $lab $t)
        !          1662:       echo No such location.
        !          1663:    if(~ $lab [hH]olmdel){
        !          1664:       echo You win.
        !          1665:       exit
        !          1666:    }
        !          1667: }
        !          1668: .P2
        !          1669: .KE
        !          1670: .LP
        !          1671: This script is worth describing in detail
        !          1672: (rather, it would be if it weren't so silly.)
        !          1673: .PP
        !          1674: Variable
        !          1675: .CW $t
        !          1676: is an abbreviation for the name of a temporary file.
        !          1677: Including
        !          1678: .CW $pid
        !          1679: in the names of temporary files insures that their
        !          1680: names won't collide, in case more than one instance
        !          1681: of the script is running at a time.
        !          1682: .PP
        !          1683: Function
        !          1684: .CW read 's
        !          1685: argument is the name of a variable into which a
        !          1686: line gathered from standard input is read.
        !          1687: .CW $ifs
        !          1688: is set to just a newline.  Thus
        !          1689: .CW read 's
        !          1690: input is not split apart at spaces, but the terminating
        !          1691: newline is deleted.
        !          1692: .PP
        !          1693: A handler is set to catch
        !          1694: .CW sigint ,
        !          1695: .CW sigquit ,
        !          1696: and
        !          1697: .CW sighup,
        !          1698: and the artificial
        !          1699: .CW sigexit
        !          1700: signal.  It just removes the temporary file and exits.
        !          1701: .PP
        !          1702: The temporary file is initialized from a here
        !          1703: document containing a list of Bell Labs locations, and
        !          1704: the main loop starts.
        !          1705: .PP
        !          1706: First, the program guesses a location (in
        !          1707: .CW $lab )
        !          1708: using the
        !          1709: .CW fortune
        !          1710: program to pick a random line from the location list.
        !          1711: It prints the location, and if it guessed Holmdel, prints
        !          1712: a message and exits.
        !          1713: .PP
        !          1714: Then it uses the
        !          1715: .CW read
        !          1716: function to get lines from standard input and validity-check
        !          1717: them until it gets a legal name.
        !          1718: Note that the condition part of a
        !          1719: .CW while
        !          1720: can be a compound command.  Only the exit status of the
        !          1721: last command in the sequence is checked.
        !          1722: .PP
        !          1723: Again, if the result
        !          1724: is Holmdel, it prints a message and exits.
        !          1725: Otherwise it goes back to the top of the loop.
        !          1726: .NH
        !          1727: Discussion
        !          1728: .PP
        !          1729: Steve Bourne's
        !          1730: .CW /bin/sh
        !          1731: is extremely well-designed; any successor is bound to
        !          1732: suffer in comparison.  I have tried to fix its
        !          1733: best-acknowledged shortcomings and to simplify things
        !          1734: wherever possible, usually by omitting unessential features.
        !          1735: Only when irresistibly tempted have I introduced novel ideas.
        !          1736: Obviously I have tinkered extensively with Bourne's syntax,
        !          1737: that being where his work was most open to criticism.
        !          1738: .PP
        !          1739: The most important principle in
        !          1740: .I rc 's
        !          1741: design is that it's not a macro processor.  Input is never
        !          1742: scanned more than once by the lexical and syntactic analysis
        !          1743: code (except, of course, by the
        !          1744: .CW eval
        !          1745: command, whose
        !          1746: .I "raison d'etre
        !          1747: is to break the rule).
        !          1748: .PP
        !          1749: Bourne shell scripts can often be made
        !          1750: to run wild by passing them arguments containing spaces.
        !          1751: These will be split into multiple arguments using
        !          1752: .CW IFS ,
        !          1753: often as inopportune times.
        !          1754: In
        !          1755: .I rc ,
        !          1756: values of variables, including command line arguments, are not re-read
        !          1757: when substituted into a command.
        !          1758: Arguments have presumably been scanned in the parent process, and ought
        !          1759: not to be re-read.
        !          1760: .PP
        !          1761: Why does Bourne re-scan commands after variable substitution?
        !          1762: He needs to be able to store lists of arguments in variables whose values are
        !          1763: character strings.
        !          1764: If we eliminate re-scanning, we must change the type of variables, so that
        !          1765: they can explicitly carry lists of strings.
        !          1766: .PP
        !          1767: This introduces some
        !          1768: conceptual complications.  We need a notation for lists of words.
        !          1769: There are two different kinds of concatenation, for strings \(em
        !          1770: .CW $a^$b ,
        !          1771: and lists \(em
        !          1772: .CW "($a $b)" .
        !          1773: The difference between
        !          1774: .CW ()
        !          1775: and
        !          1776: .CW ''
        !          1777: is confusing to novices,
        !          1778: although the distinction is arguably sensible \(em
        !          1779: a null argument is not the same as no argument.
        !          1780: .PP
        !          1781: Bourne also rescans input when doing command substitution.
        !          1782: This is because the text enclosed in back-quotes is not
        !          1783: properly a string, but a command.  Properly, it ought to
        !          1784: be parsed when the enclosing command is, but this makes
        !          1785: it difficult to
        !          1786: handle nested command substitutions, like this:
        !          1787: .P1                            
        !          1788: size=`wc -l \e`ls -t|sed 1q\e``
        !          1789: .P2
        !          1790: The inner back-quotes must be escaped
        !          1791: to avoid terminating the outer command.
        !          1792: This can get much worse than the above example;
        !          1793: the number of
        !          1794: .CW \e 's
        !          1795: required is exponential in the nesting depth.
        !          1796: .I Rc
        !          1797: fixes this by making the backquote a unary operator
        !          1798: whose argument is a command, like this:
        !          1799: .P1
        !          1800: size=`{wc -l `{ls -t|sed 1q}}
        !          1801: .P2
        !          1802: No escapes are ever required, and the whole thing
        !          1803: is parsed in one pass.
        !          1804: .PP
        !          1805: A similar rationale explains why
        !          1806: .I rc
        !          1807: defines signal handlers as though they were functions,
        !          1808: instead of associating a string with each signal, as Bourne does,
        !          1809: with the attendant possibility of getting a syntax error message
        !          1810: in response to typing the interrupt character.  Since
        !          1811: .I rc
        !          1812: parses input when typed, it reports errors when you make them.
        !          1813: .PP
        !          1814: For all this trouble, we gain substantial semantic simplifications.
        !          1815: There is no need for the distinction between
        !          1816: .CW $*
        !          1817: and
        !          1818: .CW $@ .
        !          1819: There is no need for four types of quotation, nor the
        !          1820: extremely complicated rules that govern them.  In
        !          1821: .I rc
        !          1822: you use quotation marks exactly when you want a syntax character
        !          1823: to appear in an argument.
        !          1824: .CW IFS
        !          1825: is no longer used, except in the one case where it was indispensable:
        !          1826: converting command output into argument lists during command substitution.
        !          1827: .PP
        !          1828: This also avoids an important security hole|reference(reeds loophole).
        !          1829: .I System (3)
        !          1830: and
        !          1831: .I popen (3)
        !          1832: call
        !          1833: .CW /bin/sh
        !          1834: to execute a command.  It is impossible to use either
        !          1835: of these routines with any assurance that the specified command will
        !          1836: be executed, even if the caller of
        !          1837: .I system
        !          1838: or
        !          1839: .I popen
        !          1840: specifies a full path name for the command.  This can be devastating
        !          1841: if it occurs in a set-userid program.
        !          1842: The problem is that
        !          1843: .CW IFS
        !          1844: is used to split the command into words, so an attacker can just
        !          1845: set
        !          1846: .CW IFS=/
        !          1847: in his environment and leave a Trojan horse
        !          1848: named
        !          1849: .CW usr
        !          1850: or
        !          1851: .CW bin
        !          1852: in the current working directory before running the privileged program.
        !          1853: .I Rc
        !          1854: fixes this by not ever rescanning input for any reason.
        !          1855: .PP
        !          1856: Most of the other differences between
        !          1857: .I rc
        !          1858: and the Bourne shell are not so serious.  I eliminated Bourne's
        !          1859: peculiar forms of variable substitution, like
        !          1860: .P1
        !          1861: echo ${a=b} ${c-d} ${e?error}
        !          1862: .P2
        !          1863: because they are little used, redundant and easily
        !          1864: expressed in less abstruse terms.
        !          1865: I deleted the builtins
        !          1866: .CW export ,
        !          1867: .CW readonly ,
        !          1868: .CW break ,
        !          1869: .CW continue ,
        !          1870: .CW read ,
        !          1871: .CW return ,
        !          1872: .CW set ,
        !          1873: .CW times
        !          1874: and
        !          1875: .CW unset
        !          1876: because they seem redundant or
        !          1877: only marginally useful.
        !          1878: .PP
        !          1879: Where Bourne's syntax draws from Algol 68,
        !          1880: .I rc 's
        !          1881: is based on C or Awk.  This is harder to defend.
        !          1882: I believe that, for example
        !          1883: .P1
        !          1884: if(test -f junk) rm junk
        !          1885: .P2
        !          1886: is better syntax than
        !          1887: .P1
        !          1888: if test -f junk; then rm junk; fi
        !          1889: .P2
        !          1890: because it is less cluttered with keywords,
        !          1891: it avoids the semicolons that Bourne requires
        !          1892: in odd places,
        !          1893: and the syntax characters better set off the
        !          1894: active parts of the command.
        !          1895: .PP
        !          1896: The one bit of large-scale syntax that Bourne
        !          1897: unquestionably does better than
        !          1898: .I rc
        !          1899: is the
        !          1900: .CW if
        !          1901: statement with
        !          1902: .CW "else
        !          1903: clause.
        !          1904: .I Rc 's
        !          1905: .CW if
        !          1906: has no terminating
        !          1907: .CW fi -like
        !          1908: bracket.  As a result, the parser cannot
        !          1909: tell whether or not to expect an
        !          1910: .CW "else
        !          1911: clause without looking ahead in its input.
        !          1912: The problem is that after reading, for example
        !          1913: .P1
        !          1914: if(test -f junk) echo junk found
        !          1915: .P2
        !          1916: in interactive mode,
        !          1917: .I rc
        !          1918: cannot decide whether to execute it immediately and print
        !          1919: .CW $prompt(1) ,
        !          1920: or to print
        !          1921: .CW $prompt(2)
        !          1922: and wait for the
        !          1923: .CW "else
        !          1924: to be typed.
        !          1925: In the Bourne shell, this is not a problem, because the
        !          1926: .CW if
        !          1927: command must end with
        !          1928: .CW fi ,
        !          1929: regardless of whether it contains an
        !          1930: .CW else
        !          1931: or not.
        !          1932: .PP
        !          1933: .I Rc 's
        !          1934: admittedly feeble solution is to declare that the
        !          1935: .CW else
        !          1936: clause is a separate statement, with the semantic
        !          1937: proviso that it must immediately follow an
        !          1938: .CW if ,
        !          1939: and to call it
        !          1940: .CW "if not
        !          1941: rather than
        !          1942: .CW else ,
        !          1943: as a reminder that something odd is going on.
        !          1944: The only noticeable consequences of this is that
        !          1945: the braces are required in the construction
        !          1946: .P1
        !          1947: for(i){
        !          1948:     if(test -f $i) echo $i found
        !          1949:     if not echo $i not found
        !          1950: }
        !          1951: .P2
        !          1952: and that
        !          1953: .I rc
        !          1954: resolves the ``dangling else'' ambiguity in opposition
        !          1955: to most people's expectations.
        !          1956: .PP
        !          1957: It is remarkable that in the four most recent editions of the UNIX
        !          1958: programmer's manual the Bourne shell grammar described in the manual page
        !          1959: does not admit the command
        !          1960: .CW who|wc .
        !          1961: This is surely an oversight, but it suggests something darker:
        !          1962: nobody really knows what the Bourne shell's grammar is.  Even examination
        !          1963: of the source code is little help.  The parser is implemented by recursive
        !          1964: descent, but the routines corresponding to the syntactic categories all
        !          1965: have a flag argument that subtly changes their operation depending on the
        !          1966: context.
        !          1967: .I Rc 's
        !          1968: parser is implemented using
        !          1969: .I yacc ,
        !          1970: so I can say precisely what the grammar is \(em it's reproduced in the appendix.
        !          1971: .PP
        !          1972: Its lexical structure is harder to describe.
        !          1973: I would simplify it considerably
        !          1974: except for two things.
        !          1975: There is a lexical kludge to distinguish between parentheses that immediately
        !          1976: follow a word with no intervening spaces and those that don't that I would
        !          1977: eliminate if there were a reasonable pair of characters to use
        !          1978: for subscript brackets.  I could also eliminate the insertion of
        !          1979: free carets if users were not adamant about it.
        !          1980: .NH
        !          1981: Acknowledgements
        !          1982: .PP
        !          1983: Rob Pike, Howard Trickey and other Plan 9 users have been insistent, incessant
        !          1984: sources of good ideas and criticism.  Some examples in this document are plagiarized
        !          1985: from |reference(bstj shell), as are most of
        !          1986: .I rc 's
        !          1987: good features.
        !          1988: .NH
        !          1989: References
        !          1990: .LP
        !          1991: |reference_placement
        !          1992: .SH
        !          1993: Appendix \(em an
        !          1994: .I rc
        !          1995: grammar
        !          1996: .PP
        !          1997: Below is reproduced
        !          1998: .I rc 's
        !          1999: .I yacc
        !          2000: grammar, extracted directly from the source code, edited only
        !          2001: to remove semantic actions.  The grammar describes a single
        !          2002: command.  An
        !          2003: .I rc
        !          2004: script is a sequence of zero or more of these.
        !          2005: .PP
        !          2006: In the grammar, the token
        !          2007: .CW WORD
        !          2008: represents either a quoted string or
        !          2009: a non-empty string of characters other
        !          2010: than blank, tab, newline or any of the following:
        !          2011: .P1
        !          2012: # ; & | ^ $ = ` ' { } ( ) < >
        !          2013: .P2
        !          2014: with the proviso that a word that immediately follows a
        !          2015: .CW $
        !          2016: or
        !          2017: .CW $#
        !          2018: ends at the first character that is not alphanumeric or
        !          2019: .CW _
        !          2020: or
        !          2021: .CW * .
        !          2022: .PP
        !          2023: The token
        !          2024: .CW SUB
        !          2025: represents a left parenthesis that follows a
        !          2026: .CW WORD
        !          2027: with no intervening spaces and therefore should be interpreted
        !          2028: as the start of a subscript.
        !          2029: .CW REDIR
        !          2030: represents any of the redirection symbols,
        !          2031: .P1
        !          2032: > >[\fIn\fT]
        !          2033: < <[\fIn\fT]
        !          2034: >> >>[\fIn\fT]
        !          2035: << <<[\fIn\fT]
        !          2036: .P2
        !          2037: .CW PIPE
        !          2038: is any of the pipe symbols
        !          2039: .P1
        !          2040: | |[\fIn\fT] |[\fIn\fT=\fIm\fT]
        !          2041: .P2
        !          2042: .CW DUP
        !          2043: is any of the file-descriptor duplication or closing symbols
        !          2044: .P1
        !          2045: >[\fIn\fT=\fIm\fT] <[\fIn\fT=\fIm\fT] >>[\fIn\fT=\fIm\fT]
        !          2046: >[\fIn\fT=] <[\fIn\fT=] >>[\fIn\fT=]
        !          2047: .P2
        !          2048: .CW ANDAND
        !          2049: stands for
        !          2050: .CW && ,
        !          2051: .CW OROR
        !          2052: stands for
        !          2053: .CW || ,
        !          2054: and
        !          2055: .CW COUNT
        !          2056: stands for
        !          2057: .CW $# .
        !          2058: The other token names stand for or key words, which are lexically
        !          2059: indistinguishable from
        !          2060: .CW WORD s:
        !          2061: .P1
        !          2062: BANG   !
        !          2063: FN     fn
        !          2064: FOR    for
        !          2065: IF     if
        !          2066: IN     in
        !          2067: NOT    not
        !          2068: SUBSHELL       @
        !          2069: SWITCH switch
        !          2070: TWIDDLE        ~
        !          2071: WHILE  while
        !          2072: .P2
        !          2073: .PP
        !          2074: Comments start with
        !          2075: .CW #
        !          2076: and continue to the end of the line, and are deleted by lexical
        !          2077: analysis, which also converts a backslash
        !          2078: .CW \e ) (
        !          2079: followed by a newline into a space, and
        !          2080: inserts free carets whenever a
        !          2081: .CW WORD
        !          2082: is followed by another
        !          2083: .CW WORD
        !          2084: or a
        !          2085: .CW `
        !          2086: or
        !          2087: .CW $ ,
        !          2088: with no intervening spaces.
        !          2089: .PP
        !          2090: Here then is
        !          2091: .I rc 's
        !          2092: grammar.  Semantic actions that call function
        !          2093: .CW skipnl
        !          2094: have been included at places where a command
        !          2095: may be continued on a new line.
        !          2096: .br
        !          2097: \X'PARM CT 80'
        !          2098: .KS
        !          2099: .P1
        !          2100: %term FOR IN WHILE IF NOT
        !          2101: %term TWIDDLE BANG SUBSHELL
        !          2102: %term SWITCH FN WORD REDIR DUP
        !          2103: %term PIPE SUB
        !          2104: %left IF WHILE FOR SWITCH ')' NOT
        !          2105: %left ANDAND OROR
        !          2106: %left BANG SUBSHELL
        !          2107: %left PIPE
        !          2108: %left '^'
        !          2109: %right '$' COUNT
        !          2110: %left SUB
        !          2111: %%
        !          2112: rc:
        !          2113:        |  line '\en'
        !          2114: line: cmd
        !          2115:        |  cmdsa line
        !          2116: body: cmd
        !          2117:        |  cmdsan body
        !          2118: cmdsa: cmd ';'
        !          2119:        |  cmd '&'
        !          2120: cmdsan: cmdsa
        !          2121:        |  cmd '\en'
        !          2122: brace: '{' body '}'
        !          2123: paren: '(' body ')'
        !          2124: assign: first '=' word
        !          2125: epilog:
        !          2126:        |  redir epilog
        !          2127: redir: REDIR word
        !          2128:        |  DUP
        !          2129: cmd:
        !          2130:        |  brace epilog
        !          2131:        |  IF paren {skipnl();} cmd
        !          2132:        |  IF NOT {skipnl();} cmd
        !          2133:        |  FOR '(' word IN words ')'
        !          2134:         {skipnl();} cmd
        !          2135:        |  FOR '(' word ')'
        !          2136:         {skipnl();} cmd
        !          2137:        |  WHILE paren {skipnl();} cmd
        !          2138:        |  SWITCH word {skipnl();} brace
        !          2139:        |  simple
        !          2140:        |  TWIDDLE word words
        !          2141:        |  cmd ANDAND cmd
        !          2142:        |  cmd OROR cmd
        !          2143:        |  cmd PIPE cmd
        !          2144:        |  redir cmd  %prec BANG
        !          2145:        |  assign cmd %prec BANG
        !          2146:        |  BANG cmd
        !          2147:        |  SUBSHELL cmd
        !          2148:        |  FN words brace
        !          2149:        |  FN words
        !          2150: .P2
        !          2151: .KE
        !          2152: .KS
        !          2153: .P1
        !          2154: simple: first
        !          2155:        |  simple word
        !          2156:        |  simple redir
        !          2157: first: comword  
        !          2158:        |  first '^' word
        !          2159: word: keyword
        !          2160:        |  comword
        !          2161:        |  word '^' word
        !          2162: comword: '$' word
        !          2163:        |  '$' word SUB words ')'
        !          2164:        |  COUNT word
        !          2165:        |  WORD
        !          2166:        |  '`' brace
        !          2167:        |  '(' words ')'
        !          2168:        |  REDIR brace
        !          2169: keyword: FOR|IN|WHILE|IF|NOT
        !          2170:        |  TWIDDLE|BANG|SUBSHELL|SWITCH
        !          2171:        |  FN
        !          2172: words:
        !          2173:        |  words word
        !          2174: .P2
        !          2175: .KE

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.