NAME
     rc, ., ~, if, for, while, fn, switch, test, echo, read, exit, env, fg,
     glob, cd, pwd - the shell and its built-in commands

SYNOPSIS
     .  file [arg...]
     ~ value pattern [pattern...]
     if(cond) body
     if not body
     while(cond) body
     for(var in list) body
     switch(value) { case pattern; cmds }
     fn name { body }
     test expression
     echo [arg...]
     read var
     exit [status]
     env [name [value]]
     fg
     glob pattern [dir]
     cd [dir]
     pwd

DESCRIPTION
     Rc is the shell.  It is a small relative of Plan 9's rc: the same word
     model, the same control flow, the same habit of treating everything as a
     file.  It is not a relative of the Bourne shell, and habits carried over
     from that direction will mislead you.

     A command line is read, its variables expanded, and split into words.
     The first word names a built-in command, then a function defined with fn,
     then a script found along $path.  Everything runs in the one process;
     there is no fork, and no external programs.

   Quoting and words
     Unquoted whitespace separates words.  Either quote character, ' or ",
     groups its contents and is removed; quotes may appear anywhere in a word,
     so a'b c'd is one word.  An empty quoted span is a real, counted, empty
     argument.

     Single quotes also suppress variable expansion.  Double quotes do not:
     echo "$user" prints the value, echo '$user' prints the four characters.

     The characters (, ) and ; are words of their own wherever they appear.

   Variables
     A word of the form name=value that is first on the line assigns a
     variable.  Variables live in /env, so they are visible as files and
     survive into anything that reads that directory.

     $name
          The value.

     ${name}
          The same, where the following character would otherwise be part of
          the name.

     $name(n)
          The nth space-separated element, counting from 1.

     $#name
          How many elements the value has.  $#* counts the arguments.

     $$   A literal dollar sign.

     Two variables are supplied by the shell: $status is the value returned by
     the last command, and $pid is always 1.  The shell also reads $cwd,
     $home, $path and $prompt.

     The caret joins words without a space: $file^.txt is the value of $file
     with .txt stuck to the end.  ^^ is a literal caret.

   Command substitution
     `{command} runs the command and replaces itself with the output, with
     trailing newlines removed.  Up to 1024 bytes are captured.  `` is a
     literal backtick.

   Pipes, conditionals, redirection
     | joins commands into a pipeline of at most four stages.  Since nothing
     forks, each stage runs to completion and its output -- up to 4096 bytes --
     is handed to the next as input.

     && runs the next command only if the previous one returned 0; || only if
     it did not.  A line holds at most eight such segments.

     > writes a file, truncating it; >> appends; < reads one.  <> opens a file
     for reading and writing at once, which is how you hold a network
     connection open across several commands.  The rc numbered forms are
     understood: <>[N]file opens on descriptor N, and >[1=N] or <[0=N]
     duplicates it onto standard output or standard input.  Ten numbered
     descriptors are available.

   Control flow
     if runs its body when the parenthesised command returns 0.  if not runs
     its body when the immediately preceding if did not run.

     while repeats its body while the test returns 0, up to 10000 times.

     for sets var to each word of the list in turn and runs the body.

     switch compares the value against each case.  A case matches only if it
     is identical to the value, or if it is a bare *, which matches anything
     and is therefore the default.  There is no fall-through and no partial-
     pattern matching here -- for that, use ~.

     A body is either one command, or several inside {}.  Inside braces, a
     newline means the same as a semicolon.

   Built-in commands
     . file [arg...]
          Read commands from file and run them in this shell.  The arguments
          become $1...$9, with $0 the file name and $* all of them.  Scripts
          may nest eight deep.  An exit inside a sourced script ends the
          script, not the shell.

     ~ value pattern...
          True if the value matches any pattern.  * matches any run of
          characters, ?  matches one.  This is rc's match operator, and the
          usual way to test a string: ~ $dial tcp!*.

     fn name { body }
          Define a function.  fn name with no body deletes it; fn alone lists
          them.  Inside, arguments are $1...$9 and $*.  Sixteen functions may
          be defined, of 512 bytes each.

     test expression
          Evaluate a condition, returning 0 for true.  See OPTIONS.

     echo arg...
          Print the arguments separated by single spaces, then a newline.  The
          whole line is written in one operation, which is what control files
          in /net and /dev require.

     read var
          Read one line into var, from the pipeline if there is one, from
          redirected input if there is one, otherwise from the keyboard.
          Returns 1 at end of input, which is what makes while (read line) {
          ... } terminate.

     exit [status]
          Leave the shell, or, inside a sourced script, leave the script.

     env [name [value]]
          With no arguments, print every variable.  With one, print that one.
          With two, set it.  The same names are readable as files in /env.

     fg   Resume the job suspended with ctrl-Z.  Its screen is restored and it
          carries on where it stopped.  There is one job slot; suspending a
          second thing loses the first.

     glob pattern [dir]
          Print the names in dir (the current directory by default) that match
          pattern, one per line.  Returns 0 if anything matched.  The shell
          does not expand patterns in ordinary command arguments, so this is
          how globbing is done: for (f in `{glob *.txt}) ....

     cd [dir]
          Change the working directory, to $home if no directory is given.
          This sets $cwd and the namespace's own idea of where you are.

     pwd  Print the working directory.

   Line editing
     Typing at the prompt, the following work: backspace, ctrl-C to abandon
     the line, ctrl-D on an empty line for end of input, ctrl-U to erase the
     line, ctrl-W to erase a word, ctrl-L to redraw.  Up and down arrows walk
     the history; PageUp and PageDown scroll the screen back; F8 forces a full
     e-paper refresh and F9 shows the dashboard.  Tab inserts spaces to the
     next four-column stop -- there is no completion.

OPTIONS
     The conditions understood by test:

     -e path
          The file exists.

     -f path
          It exists and is not a directory.

     -d path
          It is a directory.

     -s path
          It has a length greater than zero.

     -z string
          The string is empty.

     -n string
          The string is not empty.

     s1 = s2
     s1 != s2
          String comparison.

     n1 -eq n2
          Numeric comparison; also -ne, -lt, -le, -gt, -ge.

     ! expression
          Negation.

     A single argument is true when it is not the empty string.

EXAMPLES
     Source a script, passing it an argument:

     Match a dial string:

          if (~ $dial tcp!*) echo network
          if not echo local

     Walk a list:

          for (f in `{glob *.txt}) {
               echo $f
               wc -l $f
          }

     Read lines from a file and count them:

          n=0
          while (read line) {
               n=`{echo $n}
               echo $line
          }

     Define a function:

          fn hello { echo hello $1 }
          hello world

     Hold a connection open across several commands, the rc way:

          <>/net/tcp/1/data {
               echo GET / >[1=0]
               cat
          }

FILES
     /env The variables, one file each.

     /n/local/rc
          Scripts.  The default $path is /n/local/rc/bbs, /n/local/rc/games,
          /n/local/rc/lib and /n/local/rc; a command not otherwise found is
          looked for there, first by name and then with .rc appended.

     /dev/cons
          The terminal the shell reads and writes.

SEE ALSO
     cat(1), ls(1), p(1), history(1), man(1)

NOTES
     Nothing here forks.  A pipeline is a sequence of programs run one after
     another with a buffer between them, not a set of processes running at
     once, and a stage that expects to run forever will simply never hand
     over.  Given the machine, this is a fair trade: the whole shell is a few
     kilobytes of state.

     Sizes that matter in practice: a line is at most 1024 characters; a
     command may have 64 words; a variable name may have 31 characters; the
     shell will re-enter itself only four deep, counting command substitution,
     sourced scripts and loop bodies, and says so when asked for more.

BUGS
     A # is a comment only when it is the first thing on the line.  Later on a
     line it is an ordinary word, and is passed to the command along with the
     rest of the line.  Keep comments on lines of their own.

     if not must directly follow the if whose failure it answers.  Anything in
     between, including another command that succeeds, disconnects them.

     switch matches whole strings or *, nothing in between; a case of tcp!*
     matches only a value of exactly those five characters.

     Deeply nested constructs -- a sourced script running a loop whose body
     uses command substitution over a network mount -- have historically run
     the shell out of stack.  The scripts shipped in /n/local/rc are written
     flat for that reason.

FRST Computer                                                            RC(1)
