SH(1) SH(1)
NAME
sh, builtin, exit, load, loaded, local, whatis, quote, run,
set, unload, unquote - command language
SYNOPSIS
sh [ -ilxvn ] [ -c command ] [ file [ arg ... ]]
DESCRIPTION
Sh is a programmable user level interface (a shell) for
Inferno. It executes command lines read from a terminal or
a file or, with the -c flag, from sh's argument list. It can
also be used to give programmable functionality to Limbo
modules (see sh(2)).
Command Lines
A command line is a sequence of commands, separated by
ampersands or semicolons (& or ;), terminated by a newline.
The commands are executed in sequence from left to right.
Sh does not wait for a command followed by & to finish exe-
cuting before starting the following command. Whenever a
command followed by & is executed, its process id is
assigned to the sh variable $apid. Whenever a command not
followed by & exits or is terminated, the sh variable
$status gets the process's wait message (see prog(3)); it
will be the null string if the command was successful.
A number-sign (#) and any following characters up to (but
not including) the next newline are ignored, except in quo-
tation marks.
Simple Commands
A simple command is a sequence of arguments interspersed
with I/O redirections. If the first argument is the name of
a sh builtin or it is a braced command block (see Compound
Commands, below), it is executed by sh. If the first charac-
ter of the name is a brace ({), the shell tries to parse it
and execute it as a braced command block; if the parsing
fails, an exception is raised. Otherwise sh looks for an
external program to execute.
If the name ends in .dis, sh looks for a Dis module of that
name; otherwise it tries first to find a Dis module of that
name with .dis appended and failing that, it looks for an
executable file of the same name, which should be a read-
able, executable script file. If the name does not start
with a slash (/) or dot-slash (./), then the name is first
looked for relative to /dis, and then relative to the cur-
rent directory. A Dis module will be executed only if it
implements the Command interface (see command(2)); a script
file will be executed only if it starts with the characters
Page 1 Plan 9 (printed 10/26/25)
SH(1) SH(1)
``#!'' followed by the name of a file executable under the
rules above. In this case the command will be executed with
any following arguments mentioned in the #! header, followed
by the path of the script file, followed by any arguments
originally given to the command.
For example, to execute the simple command ls, sh will look
for one of the following things, in order, stopping the
search when one is found:
1) a built-in command named ``ls''.
2) a Dis module named ``/dis/ls.dis'',
3) an executable script file named ``/dis/ls'',
4) a Dis module named ``./ls.dis'',
5) an executable script file named ``./ls''.
Arguments and Variables
A number of constructions may be used where sh's syntax
requires an argument to appear. In many cases a
construction's value will be a list of arguments rather than
a single string.
The simplest kind of argument is the unquoted word: a
sequence of one or more characters none of which is a blank,
tab, newline, or any of the following:
# ; & | ^ $ ` ' { } ( ) < > " =
An unquoted word that contains any of the characters * ? [
is a pattern for matching against file names. The character
* matches any sequence of characters, ? matches any single
character, and [class] matches any character in the class.
If the first character of class is ^, the class is comple-
mented. (As this character is special to the shell, it may
only be included in a pattern if this character is quoted,
as long as the leading [ is not quoted). The class may also
contain pairs of characters separated by -, standing for all
characters lexically between the two. The character / must
appear explicitly in a pattern. 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, but rather stands for itself. Pattern matching
is done after all other operations. Thus,
x=/tmp; echo $x^/*.b
matches /tmp/*.b, rather than matching /*.b and then prefix-
ing /tmp.
A quoted word is a sequence of characters surrounded by sin-
gle quotes ('). A single quote is represented in a quoted
word by a pair of quotes ('').
Page 2 Plan 9 (printed 10/26/25)
SH(1) SH(1)
Each of the following is an argument.
(arguments)
The value of a sequence of arguments enclosed in paren-
theses is a list comprising the members of each element
of the sequence. Argument lists have no recursive
structure, although their syntax may suggest it. The
following are entirely equivalent:
echo hi there everybody
((echo) (hi there) everybody)
echo (hi
there
everybody
)
Newlines within parentheses count as simple white
space; they do not terminate the command. This can be
useful to give some more freedom of layout to commands
that take several commands as arguments, for instance
several of the commands defined in sh-std(1).
$argument
The argument after the $ is the name of a variable
whose value is substituted. Multiple levels of indi-
rection are possible. Variable values are lists of
strings. If argument is a number n, the value is the
nth element of $*, unless $* doesn't have n elements,
in which case the value is empty. Assignments to vari-
ables are described under Assignment , below.
$#argument
The value is the number of elements in the named vari-
able. A variable never assigned a value has zero ele-
ments.
$"argument
The value is a single string containing the components
of the named variable separated by spaces. A variable
with zero elements yields the empty string.
`{command}
"{command}
Sh executes the command and reads its standard output.
If backquote (`) is used, it is split into a list of
arguments, using characters in $ifs as separators. If
$ifs is not otherwise set, its value is ' \t\n'. If
doublequote (") is used, no tokenization takes place.
argument^argument
The ^ operator concatenates its two operands. If the
two operands have the same number of components, they
are concatenated pairwise. If not, then one operand
must have one component, and the other must be non-
empty, and concatenation is distributive.
${command}
Command must be a simple command with no redirections;
its first word must be the name of a builtin substitu-
tion operator. The operator is invoked and its value
substituted. See Built-in Commands, below, for more
Page 3 Plan 9 (printed 10/26/25)
SH(1) SH(1)
information on builtins.
<{command}
>{command}
The command is executed asynchronously with its stan-
dard output or standard input connected to a pipe. The
value of the argument is the name of a file referring
to the other end of the pipe. This allows the con-
struction of non-linear pipelines. For example, the
following runs two commands old and new and uses cmp to
compare their outputs
cmp <{old} <{new}
Free Carets
In most circumstances, sh will insert the ^ operator auto-
matically between words that are not separated by white
space. Whenever one of $ ' ` follows a quoted or unquoted
word or an unquoted word follows a quoted word with no
intervening blanks or tabs, a ^ is inserted between the two.
If an unquoted word immediately follows a $ and contains a
character other than an alphanumeric, underscore, or *, a ^
is inserted before the first such character. Thus
limbo -$flags $stem.b
is equivalent to
limbo -^$flags $stem^.b
Assignment
A command of the form name=value or name:=value assigns
value to the environment variable named name. Value is
either a list of arguments or an assignment statement. In
the latter case value is taken from the value assigned in
the assignment statement. If := is used, the value is
stored in the innermost local scope. A local scope is cre-
ated every time a braced block is entered, and destroyed
when the block is left. If = is used, the value is stored in
the innermost scope that contains any definition of name.
A list of names can also be used in place of name, which
causes each element of value in turn to be assigned the
respective variable name in the list. The last variable in
the list is assigned any elements that are left over. If
there are more variable names than elements in value, the
remaining elements are assigned the null list. For
instance, after the assignment:
(a b c) = one two three four five
$a is one, $b is two, and $c contains the remaining three
elements (three four five).
I/O Redirections
The sequence >file redirects the standard output file (file
Page 4 Plan 9 (printed 10/26/25)
SH(1) SH(1)
descriptor 1, normally the terminal) to the named file;
>>file appends standard output to the file. The standard
input file (file descriptor 0, also normally the terminal)
may be redirected from a file by the sequence <file, or by
the sequence <>file, which opens the file for writing as
well as reading. Note that if file is in fact a parsed
braced block, the redirection will be treated as pipe to the
given command - it is identical to the <{} operator men-
tioned above.
Redirections may be applied to a file-descriptor other than
standard input or output by qualifying the redirection oper-
ator with a number in square brackets. For example, the
diagnostic output (file descriptor 2) may be redirected by
writing limbo junk.b >[2] junk.
A file descriptor may be redirected to an already open
descriptor by writing >[fd0=fd1] or <[fd0=fd1]. Fd1 is a
previously opened file descriptor and fd0 becomes a new copy
(in the sense of sys-dup(2)) of it.
Redirections are executed from left to right. Therefore,
limbo junk.b >/dev/null >[2=1] and limbo junk.b >[2=1]
>/dev/null have different effects: the first puts standard
output in /dev/null and then puts diagnostic output in the
same place, where the second directs diagnostic output to
the terminal and sends standard output to /dev/null.
Compound Commands
A pair of commands separated by a pipe operator (|) is a
command. The standard output of the left command is sent
through a pipe to the standard input of the right command.
The pipe operator may be decorated to use different file
descriptors. |[fd] connects the output end of the pipe to
file descriptor fd rather than 1. |[fd0=fd1] connects out-
put to fd1 of the left command and input to fd0 of the right
command.
A sequence of commands separated by &, ;, or newline may be
grouped by surrounding them with braces ({}), elsewhere
referred to as a braced block. A braced block may be used
anywhere that a simple word is expected. If a simple command
is found with a braced block as its first word, the variable
$* is set to any following arguments, $0 is set to the block
itself, and the commands are executed in sequence. If a
braced block is passed as an argument, no execution takes
place: the block is converted to a functionally equivalent
string, suitable for later re-interpretation by the shell.
The null command ({}) has no effect and always gives a nil
status. For instance the following commands all produce the
same result:
echo hello world
Page 5 Plan 9 (printed 10/26/25)
SH(1) SH(1)
{echo hello world}
'{echo hello world}'
{echo $*} hello world
sh -c {echo hello world}
{$*} {echo hello world}
{$*} {{$*} {echo hello world}}
"{echo {echo hello world}}
'{echo hello' ^ ' world}'
x := {echo hello world}; $x
It is important to note that the value of $* is lost every
time a braced block is entered, so for instance, the follow-
ing command prints an empty string:
{{echo $*}} hello world
Built-in Commands
The term ``built-in command'', or just ``builtin'', is used
somewhat loosely in this document to refer to any command
that is executed directly by the shell; most built-in com-
mands are defined by externally loaded modules; there are a
few that are not, known as ``internal'' builtins, listed
below.
Given sh's ability to pass compound commands (braced blocks)
as arguments to other commands, most control-flow function-
ality that is traditionally hard-wired into a shell is in sh
implemented by loadable modules. See sh-std(1), sh-expr(1),
and sh-tk(1) for more details.
There are two classes of built-in commands; the first class,
known simply as ``builtins'', are used in the same way as
normal commands, the only difference being that builtins can
raise exceptions, while external commands cannot, as they
are run in a separate process. The second class, known as
``builtin substitutions'' can only be used as the first word
of the command in the ${} operator. The two classes exist in
different name-spaces: a builtin may do something quite
different from a builtin substitution of the same name.
In general, normal builtins perform some action or test some
condition; the return status of a normal builtin usually
indicates error status or conditional success. The rĂ´le of a
substitution builtin is to yield a value, (possibly a list)
which is substituted directly into place as part of the
argument list of a command.
@ command ...
Execute command in a subshell, allowing (for instance)
the name-space to be forked independently of main
shell.
run file ...
Execute commands from file. $* is set for the duration
to the remainder of the argument list following file.
Page 6 Plan 9 (printed 10/26/25)
SH(1) SH(1)
builtin command ...
Execute command as usual except that any command
defined by an external module is ignored in favour of
the original meaning. This command cannot be redefined
by an external module.
exit
Terminate the current process.
load path...
Load tries to load each of its arguments as a builtin
module into sh. If a module load succeeds, each builtin
command defined by that module is added to the list of
builtin commands. If there was a previous definition
of the command, it is replaced, with the exception of
internal sh builtins, which are covered up and reappear
when the module is unloaded. If a module with the same
path has already been loaded, sh does not try to load
it again. Unless the path begins with / or ./, the
shell looks in the standard builtins directory /dis/sh
for the module. If a load fails, a bad module excep-
tion is raised. The environment variable $autoload can
be set to a list of Shell modules that each instance of
sh should load automatically during its initialisation.
(More precisely, the modules are loaded when a new
Sh->Context is created: see sh(2) for details.)
unload path...
Unload undoes previous load commands. To succeed, path
must be the same as that given to a previous invocation
of load.
loaded
Loaded prints all the builtin commands currently
defined, along with the name of the module that defined
them. Internally defined commands are tagged with mod-
ule builtin.
whatis name ...
Print the value of each name in a form suitable for
input to sh. The forms are:
varname = value...
Varname is a non-nil environment variable.
load module; name
Name has been defined as a builtin by the
externally loaded module.
load module; ${name}
Name has been defined as a builtin substitu-
tion by the externally loaded module.
builtin name
Name is defined as a builtin internally by
sh.
${name}
Name is defined as a builtin substitution
internally by the shell.
pathname
The completed pathname of an external file.
Page 7 Plan 9 (printed 10/26/25)
SH(1) SH(1)
${builtin command }
Does for substitution builtin commands what builtin
does for normal commands.
${loaded}
The loaded builtin substitution yields a list of the
names of all the modules currently loaded, as passed to
load.
${quote list}
Quote yields a single element list which if reparsed by
the shell will recreate list.
${bquote list}
Same as quote except that items in list that are known
to be well-formed command blocks are not quoted.
${unquote arg}
Unquote reverses the operation of quote, yielding the
original list of values. For example, ${unquote ${quote
list}} yields list. A list quoted with bquote can only
be unquoted by parsing.
Environment
The environment is a list of strings made available to
externally executing commands by the env module (see
env(2)). If the env module does not exist or cannot be
loaded, no error will be reported, but no variables can be
exported to external commands. Sh creates an environment
entry for each variable whose value is non-empty. This is
formatted as if it had been run through ${quote}. Note that
in order for a variable to be exported, its name must con-
form to the restrictions imposed by env(3); names that do
not will not be exported.
When sh starts executing it reads variable definitions from
its environment.
Internally, the shell holds a context, which holds a stack
of environment variables, the current execution flags and
the list of built-in modules. A copy is made whereever par-
allel access to the context might occur. This happens for
processes executing in a pipeline, processes run asyn-
chronously with &, and in any builtin command that runs a
shell command asynchronously.
Exceptions
When sh encounters an error processing its input, an excep-
tion is raised, and if the -v flag is set, an error message
is printed to standard error. An exception causes process-
ing of the current command to terminate and control to be
transferred back up the invocation stack. In an interactive
shell, the central command processing loop catches all
exceptions and sets $status to the name of the exception.
Exceptions are not propagated between processes. Any command
that requires I/O redirection is run in a separate process,
Page 8 Plan 9 (printed 10/26/25)
SH(1) SH(1)
namely pipes (|), redirections (>, <, >>, and <>), backquote
substitution (`, ") and background processes (&). Excep-
tions can be raised and rescued using the raise and rescue
functions in the standard builtins module, std. (See sh-
std(1)). Names of exceptions raised by sh include:
parse error
An error has occurred trying to parse a command.
usage A builtin has been passed an invalid set of argu-
ments;
bad redir An error was encountered trying to open files
prior to running a process.
bad $ arg An invalid name was given to the $ or ${} opera-
tor.
no pipe Sh failed to make a pipe.
bad wait read
An error occurred while waiting for a process to
exit.
builtin not found
A substitution builtin was named but not found.
Special Variables
The following variables are set or used by sh.
$* Set to sh's argument list during initialization.
Whenever a braced block is executed, the current
value is saved and $* receives the new argument
list. The saved value is restored on completion of
the block.
$apid Whenever a process is started asynchronously with
&, $apid is set to its process id.
$ifs The input field separators used in backquote sub-
stitutions. If $ifs is not set in sh's environ-
ment, it is initialized to blank, tab and newline.
$prompt When sh is run interactively, the first component
of $prompt is printed before reading each command.
The second component is printed whenever a newline
is typed and more lines are required to complete
the command. If not set in the environment, it is
initialized by prompt=('% ' '').
$status Set to the wait message of the last-executed pro-
gram, the return status of the last-executed buil-
tin (unless started with &), or the name of the
last-raised exception, whichever is most recent.
When sh exits at end-of-file of its input, $status
is its exit status.
Page 9 Plan 9 (printed 10/26/25)
SH(1) SH(1)
Invocation
If sh is started with no arguments it reads commands from
standard input. Otherwise its first non-flag argument is
the name of a file from which to read commands (but see -c
below). Subsequent arguments become the initial value of
$*. Sh accepts the following command-line flags.
-c string Commands are read from string.
-i If -i is present, or sh is given no arguments and
its standard input is a terminal, it runs inter-
actively. Commands are prompted for using
$prompt. This option implies -v.
-l If -l is given sh reads commands from
/lib/sh/profile, if it exists, and then
./lib/profile, if it exists, before reading its
normal input.
-n Normally, sh forks its namespace on startup; if
-n is given, this behaviour is suppressed.
-v Within a non-interactive shell, informational
messages printed to standard error are usually
disabled; giving the -v flag enables them.
-x Print each simple command to stderr before exe-
cuting it.
SOURCE
/appl/cmd/sh/sh.y
SEE ALSO
sh(1), sh-std(1), sh-expr(1), sh-file2chan(1), sh-tk(1),
sh-arg(1), sh-regex(1), sh-string(1), sh-csv(1), sh(2),
env(2)
BUGS
Due to lack of system support, appending to a file with >>
will not work correctly when there are multiple concurrent
writers (but see the examples section of sh-file2chan(1) for
one solution to this).
While it is possible to use the shell as a general purpose
programming language, it is a very slow one! Intensive
tasks are best done in Limbo, which is a much safer language
to boot.
Page 10 Plan 9 (printed 10/26/25)