123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668 |
- <html>
- <title>
- data
- </title>
- <body BGCOLOR="#FFFFFF" TEXT="#000000" LINK="#0000FF" VLINK="#330088" ALINK="#FF0044">
- <H1>Rc ­ The Plan 9 Shell
- </H1>
- <DL><DD><I>Tom Duff<br>
- td@plan9.bell-labs.com<br>
- </I></DL>
- <DL><DD><H4>ABSTRACT</H4>
- <I>Rc</I>
- is a command interpreter for Plan 9 that
- provides similar facilities to UNIX's
- Bourne shell,
- with some small additions and less idiosyncratic syntax.
- This paper uses numerous examples to describe
- <I>rc</I>'s
- features, and contrasts
- <I>rc</I>
- with the Bourne shell, a model that many readers will be familiar with.
- </DL>
- <H4>1 Introduction
- </H4>
- <P>
- <I>Rc</I>
- is similar in spirit but different in detail from UNIX's
- Bourne shell. This paper describes
- <I>rc</I>'s
- principal features with many small examples and a few larger ones.
- It assumes familiarity with the Bourne shell.
- </P>
- <H4>2 Simple commands
- </H4>
- <P>
- For the simplest uses
- <I>rc</I>
- has syntax familiar to Bourne-shell users.
- All of the following behave as expected:
- <DL><DT><DD><TT><PRE>
- date
- cat /lib/news/build
- who >user.names
- who >>user.names
- wc <file
- echo [a-f]*.c
- who | wc
- who; date
- vc *.c &
- mk && v.out /*/bin/fb/*
- rm -r junk || echo rm failed!
- </PRE></TT></DL>
- </P>
- <H4>3 Quotation
- </H4>
- <P>
- An argument that contains a space or one of
- <I>rc</I>'s
- other syntax characters must be enclosed in apostrophes
- (<TT>'</TT>):
- <DL><DT><DD><TT><PRE>
- rm 'odd file name'
- </PRE></TT></DL>
- An apostrophe in a quoted argument must be doubled:
- <DL><DT><DD><TT><PRE>
- echo 'How''s your father?'
- </PRE></TT></DL>
- </P>
- <H4>4 Patterns
- </H4>
- <P>
- An unquoted argument that contains any of the characters
- <TT>*</TT>
- <TT>?</TT>
- <TT>[</TT>
- is a pattern to be matched against file names.
- A
- <TT>*</TT>
- character matches any sequence of characters,
- <TT>?</TT>
- matches any single character, and
- <TT>[</TT><I>class</I><TT>]</TT><I>
- matches any character in the
- </I><TT>class</TT><I>,
- unless the first character of
- </I><I>class</I><I>
- is
- </I><TT>~</TT><I>,
- in which case the class is complemented.
- The
- </I><I>class</I><I>
- may also contain pairs of characters separated by
- </I><TT>-</TT><I>,
- standing for all characters lexically between the two.
- The character
- </I><TT>/</TT><I>
- must appear explicitly in a pattern, as must the path name components
- </I><TT>.</TT><I>
- and
- </I><TT>..</TT><I>.
- A pattern is replaced by a list of arguments, one for each path name matched,
- except that a pattern matching no names is not replaced by the empty list;
- rather it stands for itself.
- </P>
- </I><H4>5 Variables
- </H4>
- <P>
- UNIX's Bourne shell offers string-valued variables.
- <I>Rc</I>
- provides variables whose values are lists of arguments ­
- that is, arrays of strings. This is the principal difference
- between
- <I>rc</I>
- and traditional UNIX command interpreters.
- Variables may be given values by typing, for example:
- <DL><DT><DD><TT><PRE>
- path=(. /bin)
- user=td
- font=/lib/font/bit/pelm/ascii.9.font
- </PRE></TT></DL>
- The parentheses indicate that the value assigned to
- <TT>path</TT>
- is a list of two strings. The variables
- <TT>user</TT>
- and
- <TT>font</TT>
- are assigned lists containing a single string.
- </P>
- <P>
- The value of a variable can be substituted into a command by
- preceding its name with a
- <TT></TT><I></I><TT>,
- like this:
- <DL><DT><DD><TT><PRE>
- echo </TT>path
- </PRE></TT></DL>
- If
- <TT>path</TT>
- had been set as above, this would be equivalent to
- <DL><DT><DD><TT><PRE>
- echo . /bin
- </PRE></TT></DL>
- Variables may be subscripted by numbers or lists of numbers,
- like this:
- <DL><DT><DD><TT><PRE>
- echo <I>path(2)
- echo </I>path(2 1 2)
- </PRE></TT></DL>
- These are equivalent to
- <DL><DT><DD><TT><PRE>
- echo /bin
- echo /bin . /bin
- </PRE></TT></DL>
- There can be no space separating the variable's name from the
- left parenthesis; otherwise, the subscript would be considered
- a separate parenthesized list.
- </P>
- <P>
- The number of strings in a variable can be determined by the
- <TT></TT><I>#</I><TT>
- operator. For example,
- <DL><DT><DD><TT><PRE>
- echo </TT>#path
- </PRE></TT></DL>
- would print 2 for this example.
- </P>
- <P>
- The following two assignments are subtly different:
- <DL><DT><DD><TT><PRE>
- empty=()
- null=''
- </PRE></TT></DL>
- The first sets
- <TT>empty</TT>
- to a list containing no strings.
- The second sets
- <TT>null</TT>
- to a list containing a single string,
- but the string contains no characters.
- </P>
- <P>
- Although these may seem like more or less
- the same thing (in Bourne's shell, they are
- indistinguishable), they behave differently
- in almost all circumstances.
- Among other things
- <DL><DT><DD><TT><PRE>
- echo <I>#empty
- </PRE></TT></DL>
- prints 0, whereas
- <DL><DT><DD><TT><PRE>
- echo </I>#null
- </PRE></TT></DL>
- prints 1.
- </P>
- <P>
- All variables that have never been set have the value
- <TT>()</TT>.
- </P>
- <P>
- Occasionally, it is convenient to treat a variable's value
- as a single string. The elements of a string are concatenated
- into a single string, with spaces between the elements, by
- the
- <TT></TT><I>"</I><TT>
- operator.
- Thus, if we set
- <DL><DT><DD><TT><PRE>
- list=(How now brown cow)
- string=</TT>"list
- </PRE></TT></DL>
- then both
- <DL><DT><DD><TT><PRE>
- echo <I>list
- </PRE></TT></DL>
- and
- <DL><DT><DD><TT><PRE>
- echo </I>string
- </PRE></TT></DL>
- cause the same output, viz:
- <DL><DT><DD><TT><PRE>
- How now brown cow
- </PRE></TT></DL>
- but
- <DL><DT><DD><TT><PRE>
- echo <I>#list </I>#string
- </PRE></TT></DL>
- will output
- <DL><DT><DD><TT><PRE>
- 4 1
- </PRE></TT></DL>
- because
- <TT></TT><I>list</I><TT>
- has four members, but
- </TT><TT></TT><TT>string</TT><TT>
- has a single member, with three spaces separating its words.
- </P>
- </TT><H4>6 Arguments
- </H4>
- <P>
- When
- <I>rc</I>
- is reading its input from a file, the file has access
- to the arguments supplied on
- <I>rc</I>'s
- command line. The variable
- <TT></TT><I>*</I><TT>
- initially has the list of arguments assigned to it.
- The names
- </TT><TT></TT><TT>1</TT><TT>,
- </TT><TT></TT><I>2</I><TT>,
- etc. are synonyms for
- </TT><TT></TT><TT>*(1)</TT><TT>,
- </TT><TT></TT><I>*(2)</I><TT>,
- etc.
- In addition,
- </TT><TT></TT><TT>0</TT><TT>
- is the name of the file from which
- </TT><I>rc</I><TT>'s
- input is being read.
- </P>
- </TT><H4>7 Concatenation
- </H4>
- <P>
- <I>Rc</I>
- has a string concatenation operator, the caret
- <TT>^</TT>,
- to build arguments out of pieces.
- <DL><DT><DD><TT><PRE>
- echo hully^gully
- </PRE></TT></DL>
- is exactly equivalent to
- <DL><DT><DD><TT><PRE>
- echo hullygully
- </PRE></TT></DL>
- Suppose variable
- <TT>i</TT>
- contains the name of a command.
- Then
- <DL><DT><DD><TT><PRE>
- vc <I>i^.c
- vl -o </I>1 <I>i^.v
- </PRE></TT></DL>
- might compile the command's source code, leaving the
- result in the appropriate file.
- </P>
- </I><P>
- Concatenation distributes over lists. The following
- <DL><DT><DD><TT><PRE>
- echo (a b c)^(1 2 3)
- src=(main subr io)
- cc src^.c
- </PRE></TT></DL>
- are equivalent to
- <DL><DT><DD><TT><PRE>
- echo a1 b2 c3
- cc main.c subr.c io.c
- </PRE></TT></DL>
- In detail, the rule is: if both operands of
- <TT>^</TT>
- are lists of the same non-zero number of strings, they are concatenated
- pairwise. Otherwise, if one of the operands is a single string,
- it is concatenated with each member of the other operand in turn.
- Any other combination of operands is an error.
- </P>
- <H4>8 Free carets
- </H4>
- <P>
- User demand has dictated that
- <I>rc</I>
- insert carets in certain places, to make the syntax
- look more like the Bourne shell. For example, this:
- <DL><DT><DD><TT><PRE>
- cc -<I>flags </I>stems.c
- </PRE></TT></DL>
- is equivalent to
- <DL><DT><DD><TT><PRE>
- cc -^<I>flags </I>stems^.c
- </PRE></TT></DL>
- In general,
- <I>rc</I>
- will insert
- <TT>^</TT>
- between two arguments that are not separated by white space.
- Specifically, whenever one of
- <TT></TT><I>'`</I><TT>
- follows a quoted or unquoted word, or an unquoted word follows
- a quoted word with no intervening blanks or tabs, an implicit
- </TT><TT>^</TT><TT>
- is inserted between the two. If an unquoted word immediately following a
- </TT><TT></TT><TT></TT><TT>
- contains a character other than an alphanumeric, underscore or
- </TT><TT>*</TT><TT>,
- a
- </TT><TT>^</TT><TT>
- is inserted before the first such character.
- </P>
- </TT><H4>9 Command substitution
- </H4>
- <P>
- It is often useful to build an argument list from the output of a command.
- <I>Rc</I>
- allows a command, enclosed in braces and preceded by a left quote,
- <TT>`{...}</TT>,
- anywhere that an argument is required. The command is executed and its
- standard output captured.
- The characters stored in the variable
- <TT>ifs</TT>
- are used to split the output into arguments.
- For example,
- <DL><DT><DD><TT><PRE>
- cat `{ls -tr|sed 10q}
- </PRE></TT></DL>
- will concatenate the ten oldest files in the current directory in temporal order, given the
- default
- <TT>ifs</TT>
- setting of space, tab, and newline.
- </P>
- <H4>10 Pipeline branching
- </H4>
- <P>
- The normal pipeline notation is general enough for almost all cases.
- Very occasionally it is useful to have pipelines that are not linear.
- Pipeline topologies more general than trees can require arbitrarily large pipe buffers,
- or worse, can cause deadlock.
- <I>Rc</I>
- has syntax for some kinds of non-linear but treelike pipelines.
- For example,
- <DL><DT><DD><TT><PRE>
- cmp <{old} <{new}
- </PRE></TT></DL>
- will regression-test a new version of a command.
- <TT><</TT>
- or
- <TT>></TT>
- followed by a command in braces causes the command to be run with
- its standard output or input attached to a pipe. The parent command
- (<TT>cmp</TT>
- in the example)
- is started with the other end of the pipe attached to some file descriptor
- or other, and with an argument that will connect to the pipe when opened
- (e.g.,
- <TT>/dev/fd/6</TT>).
- Some commands are unprepared to deal with input files that turn out not to be seekable.
- For example
- <TT>diff</TT>
- needs to read its input twice.
- </P>
- <H4>11 Exit status
- </H4>
- <P>
- When a command exits it returns status to the program that executed it.
- On Plan 9 status is a character string describing an error condition.
- On normal termination it is empty.
- </P>
- <P>
- <I>Rc</I>
- captures command exit status in the variable
- <TT></TT><I>status</I><TT>.
- For a simple command the value of
- </TT><TT></TT><TT>status</TT><TT>
- is just as described above. For a pipeline
- </TT><TT></TT><I>status</I><TT>
- is set to the concatenation of the statuses of the pipeline components with
- </TT><TT>|</TT><TT>
- characters for separators.
- </P>
- </TT><P>
- <I>Rc</I>
- has a several kinds of control flow,
- many of them conditioned by the status returned from previously
- executed commands. Any
- <TT></TT>status<TT>
- containing only
- </TT><TT>0</TT><TT>'s
- and
- </TT><TT>|</TT><TT>'s
- has boolean value
- </TT><I>true</I><TT>.
- Any other status is
- </TT><I>false</I><TT>.
- </P>
- </TT><H4>12 Command grouping
- </H4>
- <P>
- A sequence of commands enclosed in
- <TT>{}</TT>
- may be used anywhere a command is required.
- For example:
- <DL><DT><DD><TT><PRE>
- {sleep 3600;echo 'Time''s up!'}&
- </PRE></TT></DL>
- will wait an hour in the background, then print a message.
- Without the braces,
- <DL><DT><DD><TT><PRE>
- sleep 3600;echo 'Time''s up!'&
- </PRE></TT></DL>
- would lock up the terminal for an hour,
- then print the message in the background.
- </P>
- <H4>13 Control flow ­ <TT>for</TT>
- </H4>
- <P>
- A command may be executed once for each member of a list
- by typing, for example:
- <DL><DT><DD><TT><PRE>
- for(i in printf scanf putchar) look <I>i /usr/td/lib/dw.dat
- </PRE></TT></DL>
- This looks for each of the words
- </I><TT>printf</TT><I>,
- </I><TT>scanf</TT><I>
- and
- </I><TT>putchar</TT><I>
- in the given file.
- The general form is
- <DL><DT><DD><TT><PRE>
- for(</I><I>name</I><I> in </I><I>list</I><I>) </I><I>command</I><I>
- </PRE></TT></DL>
- or
- <DL><DT><DD><TT><PRE>
- for(</I><I>name</I><I>) </I><I>command</I><I>
- </PRE></TT></DL>
- In the first case
- </I><I>command</I><I>
- is executed once for each member of
- </I><I>list</I><I>
- with that member assigned to variable
- </I><I>name</I><I>.
- If the clause
- ``</I><TT>in</TT><I>
- </I><I>list</I><I>''
- is missing,
- ``</I><TT>in</TT><I>
- </I><TT></TT><I>*</I><TT>''
- is assumed.
- </P>
- </TT><H4>14 Conditional execution ­ <TT>if</TT>
- </H4>
- <P>
- <I>Rc</I>
- also provides a general if-statement. For example:
- <DL><DT><DD><TT><PRE>
- for(i in *.c) if(cpp <I>i >/tmp/</I>i) vc /tmp/<I>i
- </PRE></TT></DL>
- runs the C compiler on each C source program that
- cpp processes without error.
- An `if not' statement provides a two-tailed conditional.
- For example:
- <DL><DT><DD><TT><PRE>
- for(i){
- if(test -f /tmp/</I>i) echo <I>i already in /tmp
- if not cp </I>i /tmp
- }
- </PRE></TT></DL>
- This loops over each file in
- <TT></TT><I>*</I><TT>,
- copying to
- </TT><TT>/tmp</TT><TT>
- those that do not already appear there, and
- printing a message for those that do.
- </P>
- </TT><H4>15 Control flow ­ <TT>while</TT>
- </H4>
- <P>
- <I>Rc</I>'s
- while statement looks like this:
- <DL><DT><DD><TT><PRE>
- while(newer subr.v subr.c) sleep 5
- </PRE></TT></DL>
- This waits until
- <TT>subr.v</TT>
- is newer than
- <TT>subr.c</TT>,
- presumably because the C compiler finished with it.
- </P>
- <P>
- If the controlling command is empty, the loop will not terminate.
- Thus,
- <DL><DT><DD><TT><PRE>
- while() echo y
- </PRE></TT></DL>
- emulates the
- <I>yes</I>
- command.
- </P>
- <H4>16 Control flow ­ <TT>switch</TT>
- </H4>
- <P>
- <I>Rc</I>
- provides a switch statement to do pattern-matching on
- arbitrary strings. Its general form is
- <DL><DT><DD><TT><PRE>
- switch(<I>word</I>){
- case <I>pattern ...</I>
- <I>commands</I>
- case <I>pattern ...</I>
- <I>commands</I>
- ...
- }
- </PRE></TT></DL>
- <I>Rc</I>
- attempts to match the word against the patterns in each case statement in turn.
- Patterns are the same as for filename matching, except that
- <TT>/</TT>
- and
- <TT>.</TT>
- and
- <TT>..</TT>
- need not be matched explicitly.
- </P>
- <P>
- If any pattern matches, the
- commands following that case up to
- the next case (or the end of the switch)
- are executed, and execution of the switch
- is complete. For example,
- <DL><DT><DD><TT><PRE>
- switch(#*){
- case 1
- cat >><I>1
- case 2
- cat >></I>2 <<I>1
- case *
- echo 'Usage: append [from] to'
- }
- </PRE></TT></DL>
- is an append command. Called with one file argument,
- it appends its standard input to the named file. With two, the
- first is appended to the second. Any other number
- elicits an error message.
- </P>
- </I><P>
- The built-in
- <TT>~</TT>
- command also matches patterns, and is often more concise than a switch.
- Its arguments are a string and a list of patterns. It sets
- <TT></TT>status<TT>
- to true if and only if any of the patterns matches the string.
- The following example processes option arguments for the
- <A href="/magic/man2html/1/man"></TT><I>man</I><TT>(1)
- </A>command:
- <DL><DT><DD><TT><PRE>
- opt=()
- while(~ </TT><I>1 -* [1-9] 10){
- switch(</I><TT>1){
- case [1-9] 10
- sec=</TT><I>1 secn=</I><TT>1
- case -f
- c=f s=f
- case -[qwnt]
- cmd=</TT><I>1
- case -T*
- T=</I><TT>1
- case -*
- opt=(</TT><I>opt </I><TT>1)
- }
- shift
- }
- </PRE></TT></DL>
- </P>
- </TT><H4>17 Functions
- </H4>
- <P>
- Functions may be defined by typing
- <DL><DT><DD><TT><PRE>
- fn <I>name</I> { <I>commands</I> }
- </PRE></TT></DL>
- Subsequently, whenever a command named
- <I>name</I>
- is encountered, the remainder of the command's
- argument list will assigned to
- <TT></TT><I>*</I><TT>
- and
- </TT><I>rc</I><TT>
- will execute the
- </TT><I>commands</I><TT>.
- The value of
- </TT><TT></TT><TT>*</TT><TT>
- will be restored on completion.
- For example:
- <DL><DT><DD><TT><PRE>
- fn g {
- grep </TT><I>1 *.[hcyl]
- }
- </PRE></TT></DL>
- defines
- </I><TT>g</TT><I> pattern</I>n(Sf
- to look for occurrences of
- <I>pattern</I>
- in all program source files in the current directory.
- </P>
- <P>
- Function definitions are deleted by writing
- <DL><DT><DD><TT><PRE>
- fn <I>name</I>
- </PRE></TT></DL>
- with no function body.
- </P>
- <H4>18 Command execution
- </H4>
- <P>
- <I>Rc</I>
- does one of several things to execute a simple command.
- If the command name is the name of a function defined using
- <TT>fn</TT>,
- the function is executed.
- Otherwise, if it is the name of a built-in command, the
- built-in is executed directly by
- <I>rc</I>.
- Otherwise, directories mentioned in the variable
- <TT></TT>path<TT>
- are searched until an executable file is found.
- Extensive use of the
- </TT><TT></TT><I>path</I><TT>
- variable is discouraged in Plan 9. Instead, use the default
- </TT><TT>(.</TT><TT>
- </TT><TT>/bin)</TT><TT>
- and bind what you need into
- </TT><TT>/bin</TT><TT>.
- </P>
- </TT><H4>19 Built-in commands
- </H4>
- <P>
- Several commands are executed internally by
- <I>rc</I>
- because they are difficult to implement otherwise.
- </P>
- <DL COMPACT>
- <DT><TT>.<DD>
- [-i] </TT><I>file ...</I><TT></TT>.if w'<TT>. [-i] </TT><I>file ...</I><TT></TT>'-4n .br
- Execute commands from
- <I>file</I>.
- <TT></TT>*<TT>
- is set for the duration to the reminder of the argument list following
- </TT><I>file</I><TT>.
- </TT><TT></TT><I>path</I><TT>
- is used to search for
- </TT><I>file</I><TT>.
- Option
- </TT><TT>-i</TT><TT>
- indicates interactive input ­ a prompt
- (found in
- </TT><TT></TT><TT>prompt</TT><TT>)
- is printed before each command is read.
- <DT></TT><TT>b<DD>
- uiltin </TT><I>command ...</I><TT></TT>.if w'<TT>builtin </TT><I>command ...</I><TT></TT>'-4n .br
- Execute
- <I>command</I>
- as usual except that any function named
- <I>command</I>
- is ignored.
- For example,
- <DL><DT><DD><TT><PRE>
- fn cd{
- builtin cd <I>* && pwd
- }
- </PRE></TT></DL>
- defines a replacement for the
- </I><TT>cd</TT><I>
- built-in (see below) that announces the full name of the new directory.
- <DT></I><TT>c<DD>
- d [</TT><I>dir</I><TT>]</TT>.if w'<TT>cd [</TT><I>dir</I><TT>]</TT>'-4n .br
- Change the current directory to
- <I>dir</I>.
- The default argument is
- <TT></TT>home<TT>.
- </TT><TT></TT><I>cdpath</I><TT>
- is a list of places in which to search for
- </TT><I>dir</I><TT>.
- <DT></TT><TT>e<DD>
- val [</TT><I>arg ...</I><TT>]</TT>.if w'<TT>eval [</TT><I>arg ...</I><TT>]</TT>'-4n .br
- The arguments are concatenated (separated by spaces) into a string, read as input to
- <I>rc</I>,
- and executed. For example,
- <DL><DT><DD><TT><PRE>
- x='<TT>y'
- y=Doody
- eval echo Howdy, </TT><I>x
- </PRE></TT></DL>
- would echo
- <DL><DT><DD><TT><PRE>
- Howdy, Doody
- </PRE></TT></DL>
- since the arguments of
- </I><TT>eval</TT><I>
- would be
- <DL><DT><DD><TT><PRE>
- echo Howdy, </I><TT>y
- </PRE></TT></DL>
- after substituting for
- </TT><TT></TT><I>x</I><TT>.
- <DT></TT><TT>e<DD>
- xec [</TT><I>command ...</I><TT>]</TT>.if w'<TT>exec [</TT><I>command ...</I><TT>]</TT>'-4n .br
- <I>Rc</I>
- replaces itself with the given
- <I>command</I>.
- This is like a
- <I>goto</I>
- ­
- <I>rc</I>
- does not wait for the command to exit, and does not return to read any more commands.
- <DT><TT>e<DD>
- xit [</TT><I>status</I><TT>]</TT>.if w'<TT>exit [</TT><I>status</I><TT>]</TT>'-4n .br
- <I>Rc</I>
- exits immediately with the given status. If none is given, the current value of
- <TT></TT>status<TT>
- is used.
- <DT></TT><TT>f<DD>
- lag </TT><I>f</I><TT> [+-]</TT>.if w'<TT>flag </TT><I>f</I><TT> [+-]</TT>'-4n .br
- This command manipulates and tests the command line flags (described below).
- <DL><DT><DD><TT><PRE>
- flag <I>f</I><TT> +
- </PRE></TT></DL>
- sets flag
- </TT><I>f</I><TT>.
- <DL><DT><DD><TT><PRE>
- flag </TT><I>f</I><TT> -
- </PRE></TT></DL>
- clears flag
- </TT><I>f</I><TT>.
- <DL><DT><DD><TT><PRE>
- flag </TT><I>f</I><TT>
- </PRE></TT></DL>
- tests flag
- </TT><I>f</I><TT>,
- setting
- </TT><TT></TT><I>status</I><TT>
- appropriately.
- Thus
- <DL><DT><DD><TT><PRE>
- if(flag x) flag v +
- </PRE></TT></DL>
- sets the
- </TT><TT>-v</TT><TT>
- flag if the
- </TT><TT>-x</TT><TT>
- flag is already set.
- <DT></TT><TT>r<DD>
- fork [nNeEsfF]</TT>.if w'<TT>rfork [nNeEsfF]</TT>'-4n .br
- This uses the Plan 9
- <I>rfork</I>
- system entry to put
- <I>rc</I>
- into a new process group with the following attributes:
- <br><img src="data.19116850.gif"><br>
- Section
- <A href="/magic/man2html/2/fork"><I>fork</I>(2)
- </A>of the Programmer's Manual describes these attributes in more detail.
- <DT><TT>s<DD>
- hift [</TT><I>n</I><TT>]</TT>.if w'<TT>shift [</TT><I>n</I><TT>]</TT>'-4n .br
- Delete the first
- <I>n</I>
- (default 1) elements of
- <TT></TT>*<TT>.
- <DT></TT><TT>w<DD>
- ait [</TT><I>pid</I><TT>]</TT>.if w'<TT>wait [</TT><I>pid</I><TT>]</TT>'-4n .br
- Wait for the process with the given
- <I>pid</I>
- to exit. If no
- <I>pid</I>
- is given, all outstanding processes are waited for.
- <DT><TT>w<DD>
- hatis </TT><I>name ...</I><TT></TT>.if w'<TT>whatis </TT><I>name ...</I><TT></TT>'-4n .br
- Print the value of each
- <I>name</I>
- in a form suitable for input to
- <I>rc</I>.
- The output is an assignment to a variable, the definition of a function,
- a call to
- <TT>builtin</TT>
- for a built-in command, or the path name of a binary program.
- For example,
- <DL><DT><DD><TT><PRE>
- whatis path g cd who
- </PRE></TT></DL>
- might print
- <DL><DT><DD><TT><PRE>
- path=(. /bin)
- fn g {gre -e <I>1 *.[hycl]}
- builtin cd
- /bin/who
- </PRE></TT></DL>
- <DT></I><TT>~<DD>
- </TT><I>subject pattern ...</I><TT></TT>.if w'<TT>~ </TT><I>subject pattern ...</I><TT></TT>'-4n .br
- The
- <I>subject</I>
- is matched against each
- <I>pattern</I>
- in turn. On a match,
- <TT></TT>status<TT>
- is set to true.
- Otherwise, it is set to
- </TT><TT>'no match'</TT><TT>.
- Patterns are the same as for filename matching.
- The
- </TT><I>patterns</I><TT>
- are not subjected to filename replacement before the
- </TT><TT>~</TT><TT>
- command is executed, so they need not be enclosed in
- quotation marks, unless of course, a literal match for
- </TT><TT>*</TT><TT>
- </TT><TT>[</TT><TT>
- or
- </TT><TT>?</TT><TT>
- is required.
- For example
- <DL><DT><DD><TT><PRE>
- ~ </TT><I>1 ?
- </PRE></TT></DL>
- matches any single character, whereas
- <DL><DT><DD><TT><PRE>
- ~ </I><TT>1 '?'
- </PRE></TT></DL>
- only matches a literal question mark.
- </dl>
- </TT><H4>20 Advanced I/O Redirection
- </H4>
- <P>
- <I>Rc</I>
- allows redirection of file descriptors other than 0 and 1
- (standard input and output) by specifying the file descriptor
- in square brackets
- <TT>[ ]</TT>
- after the
- <TT><</TT>
- or
- <TT>></TT>.
- For example,
- <DL><DT><DD><TT><PRE>
- vc junk.c >[2]junk.diag
- </PRE></TT></DL>
- saves the compiler's diagnostics from standard error in
- <TT>junk.diag</TT>.
- </P>
- <P>
- File descriptors may be replaced by a copy, in the sense of
- <A href="/magic/man2html/2/dup"><I>dup</I>(2),
- </A>of an already-open file by typing, for example
- <DL><DT><DD><TT><PRE>
- vc junk.c >[2=1]
- </PRE></TT></DL>
- This replaces file descriptor 2 with a copy of file descriptor 1.
- It is more useful in conjunction with other redirections, like this
- <DL><DT><DD><TT><PRE>
- vc junk.c >junk.out >[2=1]
- </PRE></TT></DL>
- Redirections are evaluated from left to right, so this redirects
- file descriptor 1 to
- <TT>junk.out</TT>,
- then points file descriptor 2 at the same file.
- By contrast,
- <DL><DT><DD><TT><PRE>
- vc junk.c >[2=1] >junk.out
- </PRE></TT></DL>
- redirects file descriptor 2 to a copy of file descriptor 1
- (presumably the terminal), and then directs file descriptor 1
- to a file. In the first case, standard and diagnostic output
- will be intermixed in
- <TT>junk.out</TT>.
- In the second, diagnostic output will appear on the terminal,
- and standard output will be sent to the file.
- </P>
- <P>
- File descriptors may be closed by using the duplication notation
- with an empty right-hand side.
- For example,
- <DL><DT><DD><TT><PRE>
- vc junk.c >[2=]
- </PRE></TT></DL>
- will discard diagnostics from the compilation.
- </P>
- <P>
- Arbitrary file descriptors may be sent through
- a pipe by typing, for example,
- <DL><DT><DD><TT><PRE>
- vc junk.c |[2] grep -v '^<I>'
- </PRE></TT></DL>
- This deletes blank lines
- from the C compiler's error output. Note that the output
- of
- </I><TT>grep</TT><I>
- still appears on file descriptor 1.
- </P>
- </I><P>
- Occasionally you may wish to connect the input side of
- a pipe to some file descriptor other than zero.
- The notation
- <DL><DT><DD><TT><PRE>
- cmd1 |[5=19] cmd2
- </PRE></TT></DL>
- creates a pipeline with
- <TT>cmd1</TT>'s
- file descriptor 5 connected through a pipe to
- <TT>cmd2</TT>'s
- file descriptor 19.
- </P>
- <H4>21 Here documents
- </H4>
- <P>
- <I>Rc</I>
- procedures may include data, called ``here documents'',
- to be provided as input to commands, as in this version of the
- <I>tel</I>
- command
- <DL><DT><DD><TT><PRE>
- for(i) grep i <<!
- ...
- tor 2T-402 2912
- kevin 2C-514 2842
- bill 2C-562 7214
- ...
- !
- </PRE></TT></DL>
- A here document is introduced by the redirection symbol
- <TT><<</TT>,
- followed by an arbitrary EOF marker
- (<TT>!</TT>
- in the example). Lines following the command,
- up to a line containing only the EOF marker are saved
- in a temporary file that is connected to the command's
- standard input when it is run.
- </P>
- <P>
- <I>Rc</I>
- does variable substitution in here documents. The following command:
- <DL><DT><DD><TT><PRE>
- ed <I>3 <<EOF
- g/</I>1/s//<I>2/g
- w
- EOF
- </PRE></TT></DL>
- changes all occurrences of
- </I><TT></TT><I>1</I><TT>
- to
- </TT><TT></TT><I>2</I><TT>
- in file
- </TT><TT></TT><TT>3</TT><TT>.
- To include a literal
- </TT><TT></TT><I></I><TT>
- in a here document, type
- </TT><TT></TT><TT></TT><I></I><TT>.
- If the name of a variable is followed immediately by
- </TT><TT>^</TT><TT>,
- the caret is deleted.
- </P>
- </TT><P>
- Variable substitution can be entirely suppressed by enclosing
- the EOF marker following
- <TT><<</TT>
- in quotation marks, as in
- <TT><<'EOF'</TT>.
- </P>
- <P>
- Here documents may be provided on file descriptors other than 0 by typing, for example,
- <DL><DT><DD><TT><PRE>
- cmd <<[4]End
- ...
- End
- </PRE></TT></DL>
- </P>
- <P>
- If a here document appears within a compound block, the contents of the document
- must be after the whole block:
- <DL><DT><DD><TT><PRE>
- for(i in *){
- mail <I>i <<EOF
- }
- words to live by
- EOF
- </PRE></TT></DL>
- </P>
- </I><H4>22 Catching Notes
- </H4>
- <P>
- <I>Rc</I>
- scripts normally terminate when an interrupt is received from the terminal.
- A function with the name of a UNIX signal, in lower case, is defined in the usual way,
- but called when
- <I>rc</I>
- receives the corresponding note.
- The
- <A href="/magic/man2html/2/notify"><I>notify</I>(2)
- </A>section of the Programmer's Manual discusses notes in some detail.
- Notes of interest are:
- </P>
- <DL COMPACT>
- <DT><TT>s<DD>
- ighup</TT>.if w'<TT>sighup</TT>'-4n .br
- The note was `hangup'.
- Plan 9 sends this when the terminal has disconnected from
- <I>rc</I>.
- <DT><TT>s<DD>
- igint</TT>.if w'<TT>sigint</TT>'-4n .br
- The note was `interrupt', usually sent when
- the interrupt character (ASCII DEL) is typed on the terminal.
- <DT><TT>s<DD>
- igterm</TT>.if w'<TT>sigterm</TT>'-4n .br
- The note was `kill', normally sent by
- <A href="/magic/man2html/1/kill"><I>kill</I>(1).
- </A><DT><TT>s<DD>
- igexit</TT>.if w'<TT>sigexit</TT>'-4n .br
- An artificial note sent when
- <I>rc</I>
- is about to exit.
- </dl>
- <P>
- As an example,
- <DL><DT><DD><TT><PRE>
- fn sigint{
- rm /tmp/junk
- exit
- }
- </PRE></TT></DL>
- sets a trap for the keyboard interrupt that
- removes a temporary file before exiting.
- </P>
- <P>
- Notes will be ignored if the note routine is set to
- <TT>{}</TT>.
- Signals revert to their default behavior when their handlers'
- definitions are deleted.
- </P>
- <H4>23 Environment
- </H4>
- <P>
- The environment is a list of name-value pairs made available to
- executing binaries.
- On Plan 9, the environment is stored in a file system named
- <TT>#e</TT>,
- normally mounted on
- <TT>/env</TT>.
- The value of each variable is stored in a separate file, with components
- terminated by zero bytes.
- (The file system is
- maintained entirely in core, so no disk or network access is involved.)
- The contents of
- <TT>/env</TT>
- are shared on a per-process group basis - when a new process group is
- created it effectively attaches
- <TT>/env</TT>
- to a new file system initialized with a copy of the old one.
- A consequence of this organization is that commands can change environment
- entries and see the changes reflected in
- <I>rc</I>.
- </P>
- <P>
- Functions also appear in the environment, named by prefixing
- <TT>fn#</TT>
- to their names, like
- <TT>/env/fn#roff</TT>.
- </P>
- <H4>24 Local Variables
- </H4>
- <P>
- It is often useful to set a variable for the duration
- of a single command. An assignment followed by a command
- has this effect. For example
- <DL><DT><DD><TT><PRE>
- a=global
- a=local echo a
- echo <I>a
- </PRE></TT></DL>
- will print
- <DL><DT><DD><TT><PRE>
- local
- global
- </PRE></TT></DL>
- This works even for compound commands, like
- <DL><DT><DD><TT><PRE>
- f=/fairly/long/file/name {
- { wc </I>f; spell <I>f; diff </I>f.old <I>f } |
- pr -h 'Facts about '</I>f | lp -dfn
- }
- </PRE></TT></DL>
- </P>
- <H4>25 Examples ­ <I>cd, pwd</I>
- </H4>
- <P>
- Here is a pair of functions that provide
- enhanced versions of the standard
- <TT>cd</TT>
- and
- <TT>pwd</TT>
- commands. (Thanks to Rob Pike for these.)
- <DL><DT><DD><TT><PRE>
- ps1='% ' # default prompt
- tab=' ' # a tab character
- fn cd{
- builtin cd <I>1 &&
- switch(</I>#*){
- case 0
- dir=<I>home
- prompt=(</I>ps1 <I>tab)
- case *
- switch(</I>1)
- case /*
- dir=<I>1
- prompt=(`{basename `{pwd}}^</I>ps1 <I>tab)
- case */* ..*
- dir=()
- prompt=(`{basename `{pwd}}^</I>ps1 <I>tab)
- case *
- dir=()
- prompt=(</I>1^<I>ps1 </I>tab)
- }
- }
- }
- fn pwd{
- if(~ <I>#dir 0)
- dir=`{/bin/pwd}
- echo </I>dir
- }
- </PRE></TT></DL>
- Function
- <TT>pwd</TT>
- is a version of the standard
- <TT>pwd</TT>
- that caches its value in variable
- <TT></TT><I>dir</I><TT>,
- because the genuine
- </TT><TT>pwd</TT><TT>
- can be quite slow to execute.
- (Recent versions of Plan 9 have very fast implementations of
- </TT><TT>pwd</TT><TT>,
- reducing the advantage of the
- </TT><TT>pwd</TT><TT>
- function.)
- </P>
- </TT><P>
- Function
- <TT>cd</TT>
- calls the
- <TT>cd</TT>
- built-in, and checks that it was successful.
- If so, it sets
- <TT></TT>dir<TT>
- and
- </TT><TT></TT><I>prompt</I><TT>.
- The prompt will include the last component of the
- current directory (except in the home directory,
- where it will be null), and
- </TT><TT></TT><TT>dir</TT><TT>
- will be reset either to the correct value or to
- </TT><TT>()</TT><TT>,
- so that the
- </TT><TT>pwd</TT><TT>
- function will work correctly.
- </P>
- </TT><H4>26 Examples ­ <I>man</I>
- </H4>
- <P>
- The
- <I>man</I>
- command prints pages of the Programmer's Manual.
- It is called, for example, as
- <DL><DT><DD><TT><PRE>
- man 2 sinh
- man rc
- man -t cat
- </PRE></TT></DL>
- In the first case, the page for
- <I>sinh</I>
- in section 2 is printed.
- In the second case, the manual page for
- <I>rc</I>
- is printed. Since no manual section is specified,
- all sections are searched for the page, and it is found
- in section 1.
- In the third case, the page for
- <I>cat</I>
- is typeset (the
- <TT>-t</TT>
- option).
- <DL><DT><DD><TT><PRE>
- cd /sys/man || {
- echo <I>0: No manual! >[1=2]
- exit 1
- }
- NT=n # default nroff
- s='*' # section, default try all
- for(i) switch(</I>i){
- case -t
- NT=t
- case -n
- NT=n
- case -*
- echo Usage: <I>0 '[-nt] [section] page ...' >[1=2]
- exit 1
- case [1-9] 10
- s=</I>i
- case *
- eval 'pages='<I>s/</I>i
- for(page in <I>pages){
- if(test -f </I>page)
- <I>NT^roff -man </I>page
- if not
- echo <I>0: </I>i not found >[1=2]
- }
- }
- </PRE></TT></DL>
- Note the use of
- <TT>eval</TT>
- to make a list of candidate manual pages.
- Without
- <TT>eval</TT>,
- the
- <TT>*</TT>
- stored in
- <TT></TT><I>s</I><TT>
- would not trigger filename matching
- ­ it's enclosed in quotation marks,
- and even if it weren't, it would be expanded
- when assigned to
- </TT><TT></TT><TT>s</TT><TT>.
- Eval causes its arguments
- to be re-processed by
- </TT><I>rc</I><TT>'s
- parser and interpreter, effectively delaying
- evaluation of the
- </TT><TT>*</TT><TT>
- until the assignment to
- </TT><TT></TT><I>pages</I><TT>.
- </P>
- </TT><H4>27 Examples ­ <I>holmdel</I>
- </H4>
- <P>
- The following
- <I>rc</I>
- script plays the deceptively simple game
- <I>holmdel</I>,
- in which the players alternately name Bell Labs locations,
- the winner being the first to mention Holmdel.
- <DL><DT><DD><TT><PRE>
- t=/tmp/holmdelpid
- fn read{
- <I>1=`{awk '{print;exit}'}
- }
- ifs='
- ' # just a newline
- fn sigexit sigint sigquit sighup{
- rm -f </I>t
- exit
- }
- cat <<'!' ><I>t
- Allentown
- Atlanta
- Cedar Crest
- Chester
- Columbus
- Elmhurst
- Fullerton
- Holmdel
- Indian Hill
- Merrimack Valley
- Morristown
- Neptune
- Piscataway
- Reading
- Short Hills
- South Plainfield
- Summit
- Whippany
- West Long Branch
- !
- while(){
- lab=`{fortune </I>t}
- echo <I>lab
- if(~ </I>lab Holmdel){
- echo You lose.
- exit
- }
- while(read lab; ! grep -i -s <I>lab </I>t) echo No such location.
- if(~ <I>lab [hH]olmdel){
- echo You win.
- exit
- }
- }
- </PRE></TT></DL>
- </P>
- </I><P>
- This script is worth describing in detail
- (rather, it would be if it weren't so silly.)
- </P>
- <P>
- Variable
- <TT></TT>t<TT>
- is an abbreviation for the name of a temporary file.
- Including
- </TT><TT></TT><I>pid</I><TT>,
- initialized by
- </TT><I>rc</I><TT>
- to its process-id,
- in the names of temporary files insures that their
- names won't collide, in case more than one instance
- of the script is running at a time.
- </P>
- </TT><P>
- Function
- <TT>read</TT>'s
- argument is the name of a variable into which a
- line gathered from standard input is read.
- <TT></TT>ifs<TT>
- is set to just a newline. Thus
- </TT><TT>read</TT><TT>'s
- input is not split apart at spaces, but the terminating
- newline is deleted.
- </P>
- </TT><P>
- A handler is set to catch
- <TT>sigint</TT>,
- <TT>sigquit</TT>,
- and
- <TT>sighup,</TT>
- and the artificial
- <TT>sigexit</TT>
- signal. It just removes the temporary file and exits.
- </P>
- <P>
- The temporary file is initialized from a here
- document containing a list of Bell Labs locations, and
- the main loop starts.
- </P>
- <P>
- First, the program guesses a location (in
- <TT></TT><I>lab</I><TT>)
- using the
- </TT><TT>fortune</TT><TT>
- program to pick a random line from the location list.
- It prints the location, and if it guessed Holmdel, prints
- a message and exits.
- </P>
- </TT><P>
- Then it uses the
- <TT>read</TT>
- function to get lines from standard input and validity-check
- them until it gets a legal name.
- Note that the condition part of a
- <TT>while</TT>
- can be a compound command. Only the exit status of the
- last command in the sequence is checked.
- </P>
- <P>
- Again, if the result
- is Holmdel, it prints a message and exits.
- Otherwise it goes back to the top of the loop.
- </P>
- <H4>28 Design Principles
- </H4>
- <P>
- <I>Rc</I>
- draws heavily from Steve Bourne's
- <TT>/bin/sh</TT>.
- Any successor of the Bourne shell is bound to
- suffer in comparison. I have tried to fix its
- best-acknowledged shortcomings and to simplify things
- wherever possible, usually by omitting inessential features.
- Only when irresistibly tempted have I introduced novel ideas.
- Obviously I have tinkered extensively with Bourne's syntax.
- </P>
- <P>
- The most important principle in
- <I>rc</I>'s
- design is that it's not a macro processor. Input is never
- scanned more than once by the lexical and syntactic analysis
- code (except, of course, by the
- <TT>eval</TT>
- command, whose
- <I>raison d'être</I>
- is to break the rule).
- </P>
- <P>
- Bourne shell scripts can often be made
- to run wild by passing them arguments containing spaces.
- These will be split into multiple arguments using
- <TT>IFS</TT>,
- often at inopportune times.
- In
- <I>rc</I>,
- values of variables, including command line arguments, are not re-read
- when substituted into a command.
- Arguments have presumably been scanned in the parent process, and ought
- not to be re-read.
- </P>
- <P>
- Why does Bourne re-scan commands after variable substitution?
- He needs to be able to store lists of arguments in variables whose values are
- character strings.
- If we eliminate re-scanning, we must change the type of variables, so that
- they can explicitly carry lists of strings.
- </P>
- <P>
- This introduces some
- conceptual complications. We need a notation for lists of words.
- There are two different kinds of concatenation, for strings ­
- <TT></TT>a^<I>b</I>,
- and lists ­
- <TT>(</TT>a <I>b)</I>.
- The difference between
- <TT>()</TT>
- and
- <TT>''</TT>
- is confusing to novices,
- although the distinction is arguably sensible ­
- a null argument is not the same as no argument.
- </P>
- <P>
- Bourne also rescans input when doing command substitution.
- This is because the text enclosed in back-quotes is not
- a string, but a command. Properly, it ought to
- be parsed when the enclosing command is, but this makes
- it difficult to
- handle nested command substitutions, like this:
- <DL><DT><DD><TT><PRE>
- size=`wc -l \`ls -t|sed 1q\``
- </PRE></TT></DL>
- The inner back-quotes must be escaped
- to avoid terminating the outer command.
- This can get much worse than the above example;
- the number of
- <TT>\</TT>'s
- required is exponential in the nesting depth.
- <I>Rc</I>
- fixes this by making the backquote a unary operator
- whose argument is a command, like this:
- <DL><DT><DD><TT><PRE>
- size=`{wc -l `{ls -t|sed 1q}}
- </PRE></TT></DL>
- No escapes are ever required, and the whole thing
- is parsed in one pass.
- </P>
- <P>
- For similar reasons
- <I>rc</I>
- defines signal handlers as though they were functions,
- instead of associating a string with each signal, as Bourne does,
- with the attendant possibility of getting a syntax error message
- in response to typing the interrupt character. Since
- <I>rc</I>
- parses input when typed, it reports errors when you make them.
- </P>
- <P>
- For all this trouble, we gain substantial semantic simplifications.
- There is no need for the distinction between
- <TT></TT>*<TT>
- and
- </TT><TT></TT><I>@</I><TT>.
- There is no need for four types of quotation, nor the
- extremely complicated rules that govern them. In
- </TT><I>rc</I><TT>
- you use quotation marks when you want a syntax character
- to appear in an argument, or an argument that is the empty string,
- and at no other time.
- </TT><TT>IFS</TT><TT>
- is no longer used, except in the one case where it was indispensable:
- converting command output into argument lists during command substitution.
- </P>
- </TT><P>
- This also avoids an important UNIX security hole.
- In UNIX, the
- <I>system</I>
- and
- <I>popen</I>
- functions call
- <TT>/bin/sh</TT>
- to execute a command. It is impossible to use either
- of these routines with any assurance that the specified command will
- be executed, even if the caller of
- <I>system</I>
- or
- <I>popen</I>
- specifies a full path name for the command. This can be devastating
- if it occurs in a set-userid program.
- The problem is that
- <TT>IFS</TT>
- is used to split the command into words, so an attacker can just
- set
- <TT>IFS=/</TT>
- in his environment and leave a Trojan horse
- named
- <TT>usr</TT>
- or
- <TT>bin</TT>
- in the current working directory before running the privileged program.
- <I>Rc</I>
- fixes this by never rescanning input for any reason.
- </P>
- <P>
- Most of the other differences between
- <I>rc</I>
- and the Bourne shell are not so serious. I eliminated Bourne's
- peculiar forms of variable substitution, like
- <DL><DT><DD><TT><PRE>
- echo {a=b} <I>{c-d} </I>{e?error}
- </PRE></TT></DL>
- because they are little used, redundant and easily
- expressed in less abstruse terms.
- I deleted the builtins
- <TT>export</TT>,
- <TT>readonly</TT>,
- <TT>break</TT>,
- <TT>continue</TT>,
- <TT>read</TT>,
- <TT>return</TT>,
- <TT>set</TT>,
- <TT>times</TT>
- and
- <TT>unset</TT>
- because they seem redundant or
- only marginally useful.
- </P>
- <P>
- Where Bourne's syntax draws from Algol 68,
- <I>rc</I>'s
- is based on C or Awk. This is harder to defend.
- I believe that, for example
- <DL><DT><DD><TT><PRE>
- if(test -f junk) rm junk
- </PRE></TT></DL>
- is better syntax than
- <DL><DT><DD><TT><PRE>
- if test -f junk; then rm junk; fi
- </PRE></TT></DL>
- because it is less cluttered with keywords,
- it avoids the semicolons that Bourne requires
- in odd places,
- and the syntax characters better set off the
- active parts of the command.
- </P>
- <P>
- The one bit of large-scale syntax that Bourne
- unquestionably does better than
- <I>rc</I>
- is the
- <TT>if</TT>
- statement with
- <TT>else</TT>
- clause.
- <I>Rc</I>'s
- <TT>if</TT>
- has no terminating
- <TT>fi</TT>-like
- bracket. As a result, the parser cannot
- tell whether or not to expect an
- <TT>else</TT>
- clause without looking ahead in its input.
- The problem is that after reading, for example
- <DL><DT><DD><TT><PRE>
- if(test -f junk) echo junk found
- </PRE></TT></DL>
- in interactive mode,
- <I>rc</I>
- cannot decide whether to execute it immediately and print
- <TT></TT><I>prompt(1)</I><TT>,
- or to print
- </TT><TT></TT><TT>prompt(2)</TT><TT>
- and wait for the
- </TT><TT>else</TT><TT>
- to be typed.
- In the Bourne shell, this is not a problem, because the
- </TT><TT>if</TT><TT>
- command must end with
- </TT><TT>fi</TT><TT>,
- regardless of whether it contains an
- </TT><TT>else</TT><TT>
- or not.
- </P>
- </TT><P>
- <I>Rc</I>'s
- admittedly feeble solution is to declare that the
- <TT>else</TT>
- clause is a separate statement, with the semantic
- proviso that it must immediately follow an
- <TT>if</TT>,
- and to call it
- <TT>if not</TT>
- rather than
- <TT>else</TT>,
- as a reminder that something odd is going on.
- The only noticeable consequence of this is that
- the braces are required in the construction
- <DL><DT><DD><TT><PRE>
- for(i){
- if(test -f <I>i) echo </I>i found
- if not echo <I>i not found
- }
- </PRE></TT></DL>
- and that
- </I><I>rc</I><I>
- resolves the ``dangling else'' ambiguity in opposition
- to most people's expectations.
- </P>
- </I><P>
- It is remarkable that in the four most recent editions of the UNIX system
- programmer's manual the Bourne shell grammar described in the manual page
- does not admit the command
- <TT>who|wc</TT>.
- This is surely an oversight, but it suggests something darker:
- nobody really knows what the Bourne shell's grammar is. Even examination
- of the source code is little help. The parser is implemented by recursive
- descent, but the routines corresponding to the syntactic categories all
- have a flag argument that subtly changes their operation depending on the
- context.
- <I>Rc</I>'s
- parser is implemented using
- <I>yacc</I>,
- so I can say precisely what the grammar is.
- </P>
- <H4>29 Acknowledgements
- </H4>
- <P>
- Rob Pike, Howard Trickey and other Plan 9 users have been insistent, incessant
- sources of good ideas and criticism. Some examples in this document are plagiarized
- from [Bourne],
- as are most of
- <I>rc</I>'s
- good features.
- </P>
- <H4>30 Reference
- </H4>
- <br> <br>
- S. R. Bourne,
- UNIX Time-Sharing System: The UNIX Shell,
- Bell System Technical Journal, Volume 57 number 6, July-August 1978
- <br> <br>
- <A href=http://www.lucent.com/copyright.html>
- Copyright</A> © 2004 Lucent Technologies Inc. All rights reserved.
- </body></html>
|