An Introduction to the UNIX Shell
S. R. Bourne
ABSTRACT
The shell is a command programming language that
provides an interface to the UNIX- operating sys-
tem. Its features include control-flow primi-
tives, parameter passing, variables and string
substitution. Constructs such as while, if then
else, case and for are available. Two-way commun-
ication is possible between the shell and com-
mands. String-valued parameters, typically file
names or flags, may be passed to a command. A
return code is set by commands that may be used to
determine control-flow, and the standard output
from a command may be used as shell input.
The shell can modify the environment in which com-
mands run. Input and output can be redirected to
files, and processes that communicate through
`pipes' can be invoked. Commands are found by
searching directories in the file system in a
sequence that can be defined by the user. Com-
mands can be read either from the terminal or from
a file, which allows command procedures to be
stored for later use.
January 15, 2013
_________________________
- UNIX is a registered trademark of The Open Group in
the U.S. and other countries.
An Introduction to the UNIX Shell
S. R. Bourne
1.0 Introduction
The shell is both a command language and a programming
language that provides an interface to the UNIX operating
system. This memorandum describes, with examples, the UNIX
shell. The first section covers most of the everyday
requirements of terminal users. Some familiarity with UNIX
is an advantage when reading this section; see, for example,
"UNIX for beginners". unix beginn kernigh 1978 Section 2
describes those features of the shell primarily intended for
use within shell procedures. These include the control-flow
primitives and string-valued variables provided by the
shell. A knowledge of a programming language would be a
help when reading this section. The last section describes
the more advanced features of the shell. References of the
form "see pipe (2)" are to a section of the UNIX manual.
seventh 1978 ritchie thompson
1.1 Simple commands
Simple commands consist of one or more words separated by
blanks. The first word is the name of the command to be
executed; any remaining words are passed as arguments to the
command. For example,
who
is a command that prints the names of users logged in. The
command
ls -l
prints a list of files in the current directory. The argu-
ment -l tells ls to print status information, size and the
creation date for each file.
1.2 Background commands
To execute a command the shell normally creates a new pro-
cess and waits for it to finish. A command may be run
without waiting for it to finish. For example,
ing & is an operator that instructs the shell not to wait
for the command to finish. To help keep track of such a
process the shell reports its process number following its
creation. A list of currently active processes may be
obtained using the ps command.
1.3 Input output redirection
Most commands produce output on the standard output that is
initially connected to the terminal. This output may be
sent to a file by writing, for example,
ls -l >file
The notation >file is interpreted by the shell and is not
passed as an argument to ls. If file does not exist then
the shell creates it; otherwise the original contents of
file are replaced with the output from ls. Output may be
appended to a file using the notation
ls -l >>file
In this case file is also created if it does not already
exist.
The standard input of a command may be taken from a file
instead of the terminal by writing, for example,
wc <file
The command wc reads its standard input (in this case
redirected from file) and prints the number of characters,
words and lines found. If only the number of lines is
required then
wc -l <file
could be used.
1.4 Pipelines and filters
The standard output of one command may be connected to the
standard input of another by writing the `pipe' operator,
indicated by |, as in,
ls -l | wc
Two commands connected in this way constitute a pipeline and
the overall effect is the same as
ls -l >file; wc <file
Pipes are unidirectional and synchronization is achieved by
halting wc when there is nothing to read and halting ls when
the pipe is full.
A filter is a command that reads its standard input,
transforms it in some way, and prints the result as output.
One such filter, grep, selects from its input those lines
that contain some specified string. For example,
ls | grep old
prints those lines, if any, of the output from ls that con-
tain the string old. Another useful filter is sort. For
example,
who | sort
will print an alphabetically sorted list of logged in users.
A pipeline may consist of more than two commands, for exam-
ple,
ls | grep old | wc -l
prints the number of file names in the current directory
containing the string old.
1.5 File name generation
Many commands accept arguments which are file names. For
example,
ls -l main.c
prints information relating to the file main.c.
The shell provides a mechanism for generating a list of file
names that match a pattern. For example,
ls -l *.c
generates, as arguments to ls, all file names in the current
directory that end in .c. The character * is a pattern that
will match any string including the null string. In general
patterns are specified as follows.
* Matches any string of characters including the
null string.
? Matches any single character.
[...] Matches any one of the characters enclosed. A
For example,
[a-z]*
matches all names in the current directory beginning with
one of the letters a through z.
/usr/fred/test/?
matches all names in the directory /usr/fred/test that con-
sist of a single character. If no file name is found that
matches the pattern then the pattern is passed, unchanged,
as an argument.
This mechanism is useful both to save typing and to select
names according to some pattern. It may also be used to
find files. For example,
echo /usr/fred/*/core
finds and prints the names of all core files in sub-
directories of /usr/fred. (echo is a standard UNIX command
that prints its arguments, separated by blanks.) This last
feature can be expensive, requiring a scan of all sub-
directories of /usr/fred.
There is one exception to the general rules given for pat-
terns. The character `.' at the start of a file name must
be explicitly matched.
echo *
will therefore echo all file names in the current directory
not beginning with `.'.
echo .*
will echo all those file names that begin with `.'. This
avoids inadvertent matching of the names `.' and `..' which
mean `the current directory' and `the parent directory'
respectively. (Notice that ls suppresses information for
the files `.' and `..'.)
1.6 Quoting
Characters that have a special meaning to the shell, such as
< > * ? | &, are called metacharacters. A complete list of
metacharacters is given in appendix B. Any character pre-
ceded by a \ is quoted and loses its special meaning, if
any. The \ is elided so that
echo \\
will echo a single \. To allow long strings to be continued
over more than one line the sequence \newline is ignored.
\ is convenient for quoting single characters. When more
than one character needs quoting the above mechanism is
clumsy and error prone. A string of characters may be
quoted by enclosing the string between single quotes. For
example,
echo xx'****'xx
will echo
xx****xx
The quoted string may not contain a single quote but may
contain newlines, which are preserved. This quoting mechan-
ism is the most simple and is recommended for casual use.
A third quoting mechanism using double quotes is also avail-
able that prevents interpretation of some but not all meta-
characters. Discussion of the details is deferred to sec-
tion 3.4.
1.7 Prompting
When the shell is used from a terminal it will issue a
prompt before reading a command. By default this prompt is
`$ '. It may be changed by saying, for example,
PS1=yesdear
that sets the prompt to be the string yesdear. If a newline
is typed and further input is needed then the shell will
issue the prompt `> '. Sometimes this can be caused by mis-
typing a quote mark. If it is unexpected then an interrupt
(DEL) will return the shell to read another command. This
prompt may be changed by saying, for example,
PS2=more
1.8 The shell and login
Following login (1) the shell is called to read and execute
commands typed at the terminal. If the user's login direc-
tory contains the file .profile then it is assumed to con-
tain commands and is read by the shell before reading any
commands from the terminal.
o ls
Print the names of files in the current directory.
o ls >file
Put the output from ls into file.
o ls | wc -l
Print the number of files in the current direc-
tory.
o ls | grep old
Print those file names containing the string old.
o ls | grep old | wc -l
Print the number of files whose name contains the
string old.
o cc pgm.c &
Run cc in the background.
The shell may be used to read and execute commands contained
in a file. For example,
sh file [ args ... ]
calls the shell to read commands from file. Such a file is
called a command procedure or shell procedure. Arguments
may be supplied with the call and are referred to in file
using the positional parameters $1, $2, .... For example,
if the file wg contains
who | grep $1
then
sh wg fred
is equivalent to
who | grep fred
UNIX files have three independent attributes, read, write
and execute. The UNIX command chmod (1) may be used to make
a file executable. For example,
chmod +x wg
will ensure that the file wg has execute status. Following
this, the command
wg fred
is equivalent to
sh wg fred
This allows shell procedures and programs to be used inter-
changeably. In either case a new process is created to run
the command.
As well as providing names for the positional parameters,
the number of positional parameters in the call is available
as $#. The name of the file being executed is available as
$0.
A special shell parameter $* is used to substitute for all
positional parameters except $0. A typical use of this is
to provide some default arguments, as in,
nroff -T450 -ms $*
2.1 Control flow - for
A frequent use of shell procedures is to loop through the
arguments ($1, $2, ...) executing commands once for each
argument. An example of such a procedure is tel that
searches the file /usr/lib/telnos that contains lines of the
form
...
fred mh0123
bert mh0789
...
The text of tel is
for i
do grep $i /usr/lib/telnos; done
The command
tel fred
prints those lines in /usr/lib/telnos that contain the
string fred.
tel fred bert
prints those lines containing fred followed by those for
bert.
The for loop notation is recognized by the shell and has the
general form
for name in w1 w2 ...
do command-list
done
A command-list is a sequence of one or more simple commands
separated or terminated by a newline or semicolon. Further-
more, reserved words like do and done are only recognized
following a newline or semicolon. name is a shell variable
that is set to the words w1 w2 ... in turn each time the
command-list following do is executed. If in w1 w2 ... is
omitted then the loop is executed once for each positional
parameter; that is, in $* is assumed.
Another example of the use of the for loop is the create
command whose text is
for i do >$i; done
create alpha beta
ensures that two empty files alpha and beta exist and are
empty. The notation >file may be used on its own to create
or clear the contents of a file. Notice also that a semi-
colon (or newline) is required before done.
2.2 Control flow - case
A multiple way branch is provided for by the case notation.
For example,
case $# in
1) cat >>$1 ;;
2) cat >>$2 <$1 ;;
*) echo 'usage: append [ from ] to' ;;
esac
is an append command. When called with one argument as
append file
$# is the string 1 and the standard input is copied onto the
end of file using the cat command.
append file1 file2
appends the contents of file1 onto file2. If the number of
arguments supplied to append is other than 1 or 2 then a
message is printed indicating proper usage.
The general form of the case command is
case word in
pattern) command-list;;
...
esac
The shell attempts to match word with each pattern, in the
order in which the patterns appear. If a match is found the
associated command-list is executed and execution of the
case is complete. Since * is the pattern that matches any
string it can be used for the default case.
A word of caution: no check is made to ensure that only one
pattern matches the case argument. The first match found
defines the set of commands to be executed. In the example
below the commands following the second * will never be exe-
cuted.
case $# in
*) ... ;;
*) ... ;;
esac
Another example of the use of the case construction is to
distinguish between different forms of an argument. The
following example is a fragment of a cc command.
for i
do case $i in
-[ocs]) ... ;;
-*) echo 'unknown flag $i' ;;
*.c) /lib/c0 $i ... ;;
*) echo 'unexpected argument $i' ;;
esac
done
To allow the same commands to be associated with more than
one pattern the case command provides for alternative pat-
terns separated by a |. For example,
case $i in
-x|-y) ...
esac
is equivalent to
case $i in
-[xy]) ...
esac
The usual quoting conventions apply so that
case $i in
\?) ...
will match the character ?.
2.3 Here documents
The shell procedure tel in section 2.1 uses the file
/usr/lib/telnos to supply the data for grep. An alternative
is to include this data within the shell procedure as a here
document, as in,
for i
do grep $i <<!
...
fred mh0123
bert mh0789
...
!
done
In this example the shell takes the lines between <<! and !
as the standard input for grep. The string ! is arbitrary,
the document being terminated by a line that consists of the
string following <<.
Parameters are substituted in the document before it is made
available to grep as illustrated by the following procedure
called edg.
ed $3 <<%
g/$1/s//$2/g
w
%
The call
edg string1 string2 file
is then equivalent to the command
ed file <<%
g/string1/s//string2/g
w
%
and changes all occurrences of string1 in file to string2.
Substitution can be prevented using \ to quote the special
character $ as in
ed $3 <<+
1,\$s/$1/$2/g
w
+
(This version of edg is equivalent to the first except that
ed will print a ? if there are no occurrences of the string
$1.) Substitution within a here document may be prevented
entirely by quoting the terminating string, for example,
grep $i <<\#
...
#
this latter form is more efficient.
2.4 Shell variables
The shell provides string-valued variables. Variable names
begin with a letter and consist of letters, digits and
underscores. Variables may be given values by writing, for
example,
user=fred box=m000 acct=mh0000
which assigns values to the variables user, box and acct. A
variable may be set to the null string by saying, for exam-
ple,
null=
The value of a variable is substituted by preceding its name
with $; for example,
echo $user
will echo fred.
Variables may be used interactively to provide abbreviations
for frequently used strings. For example,
b=/usr/fred/bin
mv pgm $b
will move the file pgm from the current directory to the
directory /usr/fred/bin. A more general notation is avail-
able for parameter (or variable) substitution, as in,
echo ${user}
which is equivalent to
echo $user
and is used when the parameter name is followed by a letter
or digit. For example,
tmp=/tmp/ps
ps a >${tmp}a
will direct the output of ps to the file /tmp/psa, whereas,
ps a >$tmpa
would cause the value of the variable tmpa to be substi-
tuted.
$? is set after executing each command.
$? The exit status (return code) of the last com-
mand executed as a decimal string. Most com-
mands return a zero exit status if they com-
plete successfully, otherwise a non-zero exit
status is returned. Testing the value of
return codes is dealt with later under if and
while commands.
$# The number of positional parameters (in
decimal). Used, for example, in the append
command to check the number of parameters.
$$ The process number of this shell (in decimal).
Since process numbers are unique among all
existing processes, this string is frequently
used to generate unique temporary file names.
For example,
ps a >/tmp/ps$$
...
rm /tmp/ps$$
$! The process number of the last process run in
the background (in decimal).
$- The current shell flags, such as -x and -v.
Some variables have a special meaning to the shell and
should be avoided for general use.
$MAIL When used interactively the shell looks at the
file specified by this variable before it
issues a prompt. If the specified file has
been modified since it was last looked at the
shell prints the message you have mail before
prompting for the next command. This variable
is typically set in the file .profile, in the
user's login directory. For example,
MAIL=/usr/mail/fred
$HOME The default argument for the cd command. The
current directory is used to resolve file name
references that do not begin with a /, and is
changed using the cd command. For example,
cd /usr/fred/bin
cat wn
will print on the terminal the file wn in this
directory. The command cd with no argument is
equivalent to
cd $HOME
This variable is also typically set in the the
user's login profile.
$PATH A list of directories that contain commands
(the search path). Each time a command is exe-
cuted by the shell a list of directories is
searched for an executable file. If $PATH is
not set then the current directory, /bin, and
/usr/bin are searched by default. Otherwise
$PATH consists of directory names separated by
:. For example,
PATH=:/usr/fred/bin:/bin:/usr/bin
specifies that the current directory (the null
string before the first :), /usr/fred/bin, /bin
and /usr/bin are to be searched in that order.
In this way individual users can have their own
`private' commands that are accessible indepen-
dently of the current directory. If the com-
mand name contains a / then this directory
search is not used; a single attempt is made to
execute the command.
$PS1 The primary shell prompt string, by default,
`$ '.
$PS2 The shell prompt when further input is needed,
by default, `> '.
$IFS The set of characters used by blank interpreta-
tion (see section 3.4).
2.5 The test command
The test command, although not part of the shell, is
intended for use by shell programs. For example,
test -f file
returns zero exit status if file exists and non-zero exit
status otherwise. In general test evaluates a predicate and
returns the result as its exit status. Some of the more
frequently used test arguments are given here, see test (1)
test s true if the argument s is not the null string
test -f file true if file exists
test -r file true if file is readable
test -w file true if file is writable
test -d file true if file is a directory
2.6 Control flow - while
The actions of the for loop and the case branch are deter-
mined by data available to the shell. A while or until loop
and an if then else branch are also provided whose actions
are determined by the exit status returned by commands. A
while loop has the general form
while command-list1
do command-list2
done
The value tested by the while command is the exit status of
the last simple command following while. Each time round
the loop command-list1 is executed; if a zero exit status is
returned then command-list2 is executed; otherwise, the loop
terminates. For example,
while test $1
do ...
shift
done
is equivalent to
for i
do ...
done
shift is a shell command that renames the positional parame-
ters $2, $3, ... as $1, $2, ... and loses $1.
Another kind of use for the while/until loop is to wait
until some external event occurs and then run some commands.
In an until loop the termination condition is reversed. For
example,
until test -f file
do sleep 300; done
commands
will loop until file exists. Each time round the loop it
waits for 5 minutes before trying again. (Presumably
another process will eventually create the file.)
Also available is a general conditional branch of the form,
if command-list
then command-list
else command-list
fi
that tests the value returned by the last simple command
following if.
The if command may be used in conjunction with the test com-
mand to test for the existence of a file as in
if test -f file
then process file
else do something else
fi
An example of the use of if, case and for constructions is
given in section 2.10.
A multiple test if command of the form
if ...
then ...
else if ...
then ...
else if ...
...
fi
fi
fi
may be written using an extension of the if notation as,
if ...
then ...
elif ...
then ...
elif ...
...
fi
The following example is the touch command which changes the
`last modified' time for a list of files. The command may
be used in conjunction with make (1) to force recompilation
of a list of files.
flag=
for i
do case $i in
-c) flag=N ;;
*) if test -f $i
then ln $i junk$$; rm junk$$
elif test $flag
then echo file \'$i\' does not exist
else >$i
fi
esac
done
The -c flag is used in this command to force subsequent
files to be created if they do not already exist. Other-
wise, if the file does not exist, an error message is
printed. The shell variable flag is set to some non-null
string if the -c argument is encountered. The commands
ln ...; rm ...
make a link to the file and then remove it thus causing the
last modified date to be updated.
The sequence
if command1
then command2
fi
may be written
command1 && command2
Conversely,
command1 || command2
executes command2 only if command1 fails. In each case the
value returned is that of the last simple command executed.
2.8 Command grouping
Commands may be grouped in two ways,
{ command-list ; }
and
( command-list )
ple,
(cd x; rm junk )
executes rm junk in the directory x without changing the
current directory of the invoking shell.
The commands
cd x; rm junk
have the same effect but leave the invoking shell in the
directory x.
2.9 Debugging shell procedures
The shell provides two tracing mechanisms to help when
debugging shell procedures. The first is invoked within the
procedure as
set -v
(v for verbose) and causes lines of the procedure to be
printed as they are read. It is useful to help isolate syn-
tax errors. It may be invoked without modifying the pro-
cedure by saying
sh -v proc ...
where proc is the name of the shell procedure. This flag
may be used in conjunction with the -n flag which prevents
execution of subsequent commands. (Note that saying set -n
at a terminal will render the terminal useless until an
end-of-file is typed.)
The command
set -x
will produce an execution trace. Following parameter sub-
stitution each command is printed as it is executed. (Try
these at the terminal to see what effect they have.) Both
flags may be turned off by saying
set -
and the current setting of the shell flags is available as
$-.
2.10 The man command
The following is the man command which is used to print sec-
man sh
man -t ed
man 2 fork
In the first the manual section for sh is printed. Since no
section is specified, section 1 is used. The second example
will typeset (-t option) the manual section for ed. The
last prints the fork manual page from section 2.
cd /usr/man
: 'colon is the comment command'
: 'default is nroff ($N), section 1 ($s)'
N=n s=1
for i
do case $i in
9 [1-9]*) s=$i ;;
9 -t) N=t ;;
9 -n) N=n ;;
9 -*) echo unknown flag \'$i\' ;;
9 *) if test -f man$s/$i.$s
then ${N}roff man0/${N}aa man$s/$i.$s
else : 'look through all manual sections'
found=no
for j in 1 2 3 4 5 6 7 8 9
do if test -f man$j/$i.$j
then man $j $i
found=yes
fi
done
case $found in
no) echo '$i: manual page not found'
esac
fi
esac
done
Figure 1. A version of the man command
9
cedure of the form name=value that precedes the command name
causes value to be assigned to name before execution of the
procedure begins. The value of name in the invoking shell
is not affected. For example,
user=fred command
will execute command with user set to fred. The -k flag
causes arguments of the form name=value to be interpreted in
this way anywhere in the argument list. Such names are
sometimes called keyword parameters. If any arguments
remain they are available as positional parameters $1, $2,
....
The set command may also be used to set positional parame-
ters from within a procedure. For example,
set - *
will set $1 to the first file name in the current directory,
$2 to the next, and so on. Note that the first argument, -,
ensures correct treatment when the first file name begins
with a -.
3.1 Parameter transmission
When a shell procedure is invoked both positional and key-
word parameters may be supplied with the call. Keyword
parameters are also made available implicitly to a shell
procedure by specifying in advance that such parameters are
to be exported. For example,
export user box
marks the variables user and box for export. When a shell
procedure is invoked copies are made of all exportable vari-
ables for use within the invoked procedure. Modification of
such variables within the procedure does not affect the
values in the invoking shell. It is generally true of a
shell procedure that it may not modify the state of its
caller without explicit request on the part of the caller.
(Shared file descriptors are an exception to this rule.)
Names whose value is intended to remain constant may be
declared readonly. The form of this command is the same as
that of the export command,
readonly name ...
If a shell parameter is not set then the null string is sub-
stituted for it. For example, if the variable d is not set
echo $d
or
echo ${d}
will echo nothing. A default string may be given as in
echo ${d-.}
which will echo the value of the variable d if it is set and
`.' otherwise. The default string is evaluated using the
usual quoting conventions so that
echo ${d-'*'}
will echo * if the variable d is not set. Similarly
echo ${d-$1}
will echo the value of d if it is set and the value (if any)
of $1 otherwise. A variable may be assigned a default value
using the notation
echo ${d=.}
which substitutes the same string as
echo ${d-.}
and if d were not previously set then it will be set to the
string `.'. (The notation ${...=...} is not available for
positional parameters.)
If there is no sensible default then the notation
echo ${d?message}
will echo the value of the variable d if it has one, other-
wise message is printed by the shell and execution of the
shell procedure is abandoned. If message is absent then a
standard message is printed. A shell procedure that
requires some parameters to be set might start as follows.
: ${user?} ${acct?} ${bin?}
...
3.3 Command substitution
The standard output from a command can be substituted in a
similar way to parameters. The command pwd prints on its
standard output the name of the current directory. For
example, if the current directory is /usr/fred/bin then the
command
d=`pwd`
is equivalent to
d=/usr/fred/bin
The entire string between grave accents (`...`) is taken as
the command to be executed and is replaced with the output
from the command. The command is written using the usual
quoting conventions except that a ` must be escaped using a
\. For example,
ls `echo "$1"`
is equivalent to
ls $1
Command substitution occurs in all contexts where parameter
substitution occurs (including here documents) and the
treatment of the resulting text is the same in both cases.
This mechanism allows string processing commands to be used
within shell procedures. An example of such a command is
basename which removes a specified suffix from a string.
For example,
basename main.c .c
will print the string main. Its use is illustrated by the
following fragment from a cc command.
case $A in
...
*.c) B=`basename $A .c`
...
esac
that sets B to the part of $A with the suffix .c stripped.
Here are some composite examples.
o set `date`; echo $6 $2 $3, $4
will print, e.g., 1977 Nov 1, 23:59:59
3.4 Evaluation and quoting
The shell is a macro processor that provides parameter sub-
stitution, command substitution and file name generation for
the arguments to commands. This section discusses the order
in which these evaluations occur and the effects of the
various quoting mechanisms.
Commands are parsed initially according to the grammar given
in appendix A. Before a command is executed the following
substitutions occur.
o parameter substitution, e.g. $user
o command substitution, e.g. `pwd`
Only one evaluation occurs so that if, for exam-
ple, the value of the variable X is the string $y
then
echo $X
will echo $y.
o blank interpretation
Following the above substitutions the resulting
characters are broken into non-blank words (blank
interpretation). For this purpose `blanks' are
the characters of the string $IFS. By default,
this string consists of blank, tab and newline.
The null string is not regarded as a word unless
it is quoted. For example,
echo ''
will pass on the null string as the first argument
to echo, whereas
echo $null
will call echo with no arguments if the variable
null is not set or set to the null string.
o file name generation
Each word is then scanned for the file pattern
The evaluations just described also occur in the list of
words associated with a for loop. Only substitution occurs
in the word used for a case branch.
As well as the quoting mechanisms described earlier using \
and '...' a third quoting mechanism is provided using double
quotes. Within double quotes parameter and command substi-
tution occurs but file name generation and the interpreta-
tion of blanks does not. The following characters have a
special meaning within double quotes and may be quoted using
\.
$ parameter substitution
` command substitution
" ends the quoted string
\ quotes the special characters $ ` " \
For example,
echo "$x"
will pass the value of the variable x as a single argument
to echo. Similarly,
echo "$*"
will pass the positional parameters as a single argument and
is equivalent to
echo "$1 $2 ..."
The notation $@ is the same as $* except when it is quoted.
echo "$@"
will pass the positional parameters, unevaluated, to echo
and is equivalent to
echo "$1" "$2" ...
The following table gives, for each quoting mechanism, the
shell metacharacters that are evaluated.
` y n n t n n
" y y n y t n
t terminator
y interpreted
n not interpreted
Figure 2. Quoting mechanisms
In cases where more than one evaluation of a string is
required the built-in command eval may be used. For exam-
ple, if the variable X has the value $y, and if y has the
value pqr then
eval echo $X
will echo the string pqr.
In general the eval command evaluates its arguments (as do
all commands) and treats the result as input to the shell.
The input is read and the resulting command(s) executed.
For example,
wg='eval who|grep'
$wg fred
is equivalent to
who|grep fred
In this example, eval is required since there is no
interpretation of metacharacters, such as |, following sub-
stitution.
3.5 Error handling
The treatment of errors detected by the shell depends on the
type of error and on whether the shell is being used
interactively. An interactive shell is one whose input and
output are connected to a terminal (as determined by gtty
(2)). A shell invoked with the -i flag is also interactive.
Execution of a command (see also 3.7) may fail for any of
the following reasons.
o Input output redirection may fail. For example, if a
file does not exist or cannot be created.
o The command itself does not exist or cannot be
a complete list of UNIX signals.
o The command terminates normally but returns a non-zero
exit status.
In all of these cases the shell will go on to execute the
next command. Except for the last case an error message
will be printed by the shell. All remaining errors cause
the shell to exit from a command procedure. An interactive
shell will return to read another command from the terminal.
Such errors include the following.
o Syntax errors. e.g., if ... then ... done
o A signal such as interrupt. The shell waits for the
current command, if any, to finish execution and then
either exits or returns to the terminal.
o Failure of any of the built-in commands such as cd.
The shell flag -e causes the shell to terminate if any error
is detected.
1 hangup
2 interrupt
3* quit
4* illegal instruction
5* trace trap
6* IOT instruction
7* EMT instruction
8* floating point exception
9 kill (cannot be caught or ignored)
10* bus error
11* segmentation violation
12* bad argument to system call
13 write on a pipe with no one to read it
14 alarm clock
15 software termination (from kill (1))
Figure 3. UNIX signals
Those signals marked with an asterisk produce a core dump if
not caught. However, the shell itself ignores quit which is
the only external signal that can cause a dump. The signals
in this list of potential interest to shell programs are 1,
2, 3, 14 and 15.
some cleaning up is required, such as removing temporary
files. For example,
trap 'rm /tmp/ps$$; exit' 2
sets a trap for signal 2 (terminal interrupt), and if this
signal is received will execute the commands
rm /tmp/ps$$; exit
exit is another built-in command that terminates execution
of a shell procedure. The exit is required; otherwise,
after the trap has been taken, the shell will resume execut-
ing the procedure at the place where it was interrupted.
UNIX signals can be handled in one of three ways. They can
be ignored, in which case the signal is never sent to the
process. They can be caught, in which case the process must
decide what action to take when the signal is received.
Lastly, they can be left to cause termination of the process
without it having to take any further action. If a signal
is being ignored on entry to the shell procedure, for exam-
ple, by invoking it in the background (see 3.7) then trap
commands (and the signal) are ignored.
The use of trap is illustrated by this modified version of
the touch command (Figure 4). The cleanup action is to
remove the file junk$$.
flag=
trap 'rm -f junk$$; exit' 1 2 3 15
for i
do case $i in
-c) flag=N ;;
*) if test -f $i
then ln $i junk$$; rm junk$$
elif test $flag
then echo file \'$i\' does not exist
else >$i
fi
esac
done
Figure 4. The touch command
The trap command appears before the creation of the tem-
porary file; otherwise it would be possible for the process
to die without removing the file.
A procedure may, itself, elect to ignore signals by specify-
ing the null string as the argument to trap. The following
fragment is taken from the nohup command.
trap '' 1 2 3 15
which causes hangup, interrupt, quit and kill to be ignored
both by the procedure and by invoked commands.
Traps may be reset by saying
trap 2 3
which resets the traps for signals 2 and 3 to their default
values. A list of the current values of traps may be
obtained by writing
trap
The procedure scan (Figure 5) is an example of the use of
trap where there is no exit in the trap command. scan takes
each directory in the current directory, prompts with its
name, and then executes commands typed at the terminal until
an end of file or an interrupt is received. Interrupts are
ignored while executing the requested commands but cause
termination when scan is waiting for input.
d=`pwd`
for i in *
do if test -d $d/$i
then cd $d/$i
while echo "$i:"
trap exit 2
read x
do trap : 2; eval $x; done
fi
done
Figure 5. The scan command
read x is a built-in command that reads one line from the
standard input and places the result in the variable x. It
returns a non-zero exit status if either an end-of-file is
read or an interrupt is received.
3.7 Command execution
To run a command (other than a built-in) the shell first
mand exec is used in the rare cases when no fork is required
and simply replaces the shell with a new command. For exam-
ple, a simple version of the nohup command looks like
trap '' 1 2 3 15
exec $*
The trap turns off the signals specified so that they are
ignored by subsequently created commands and exec replaces
the shell by the command specified.
Most forms of input output redirection have already been
described. In the following word is only subject to parame-
ter and command substitution. No file name generation or
blank interpretation takes place so that, for example,
echo ... >*.c
will write its output into a file whose name is *.c. Input
output specifications are evaluated left to right as they
appear in the command.
> word The standard output (file descriptor 1) is sent
to the file word which is created if it does not
already exist.
>> word The standard output is sent to file word. If
the file exists then output is appended (by
seeking to the end); otherwise the file is
created.
< word The standard input (file descriptor 0) is taken
from the file word.
<< word The standard input is taken from the lines of
shell input that follow up to but not including
a line consisting only of word. If word is
quoted then no interpretation of the document
occurs. If word is not quoted then parameter
and command substitution occur and \ is used to
quote the characters \ $ ` and the first charac-
ter of word. In the latter case \newline is
ignored (c.f. quoted strings).
>& digit The file descriptor digit is duplicated using
the system call dup (2) and the result is used
as the standard output.
<& digit The standard input is duplicated from file
descriptor digit.
Any of the above may be preceded by a digit in which case
the file descriptor created is that specified by the digit
instead of the default 0 or 1. For example,
... 2>file
runs a command with message output (file descriptor 2)
directed to file.
... 2>&1
runs a command with its standard output and message output
merged. (Strictly speaking file descriptor 2 is created by
duplicating file descriptor 1 but the effect is usually to
merge the two streams.)
The environment for a command run in the background such as
list *.c | lpr &
is modified in two ways. Firstly, the default standard
input for such a command is the empty file /dev/null. This
prevents two processes (the shell and the command), which
are running in parallel, from trying to read the same input.
Chaos would ensue if this were not the case. For example,
ed file &
would allow both the editor and the shell to read from the
same input at the same time.
The other modification to the environment of a background
command is to turn off the QUIT and INTERRUPT signals so
that they are ignored by the command. This allows these
signals to be used at the terminal without causing back-
ground commands to terminate. For this reason the UNIX con-
vention for a signal is that if it is set to 1 (ignored)
then it is never changed even for a short time. Note that
the shell command trap has no effect for an ignored signal.
3.8 Invoking the shell
The following flags are interpreted by the shell when it is
invoked. If the first character of argument zero is a
minus, then commands are read from the file .profile.
-c string
If the -c flag is present then commands are read from
string.
-i If the -i flag is present or if the shell input and
output are attached to a terminal (as told by gtty)
then this shell is interactive. In this case TERMINATE
is ignored (so that kill 0 does not kill an interactive
shell) and INTERRUPT is caught and ignored (so that
wait is interruptable). In all cases QUIT is ignored
by the shell.
Acknowledgements
The design of the shell is based in part on the original
UNIX shell unix command language thompson and the PWB/UNIX
shell, pwb shell mashey unix some features having been taken
from both. Similarities also exist with the command inter-
preters of the Cambridge Multiple Access System cambridge
multiple access system hartley and of CTSS. ctss
I would like to thank Dennis Ritchie and John Mashey for
many discussions during the design of the shell. I am also
grateful to the members of the Computing Science Research
Center and to Joe Maranzano for their comments on drafts of
this document.
$LIST$
simple-command: item
simple-command item
command: simple-command
( command-list )
{ command-list }
for name do command-list done
for name in word ... do command-list done
B>
while command-list do command-list done
until command-list do command-list done
case word in case-part ... esac
if command-list then command-list else-part fi
pipeline: command
pipeline | command
andor: pipeline
andor && pipeline
andor || pipeline
command-list: andor
command-list ;
command-list &
command-list ; andor
command-list & andor
input-output: > file
< file
>> word
<< word
file: word
& digit
& -
case-part: pattern ) command-list ;;
pattern: word
pattern | word
else-part: elif command-list then command-list else-part
else command-list
empty
empty:
word: a sequence of non-blank characters
name: a sequence of letters, digits or underscores starting with a letter
| pipe symbol
&& `andf' symbol
|| `orf' symbol
; command separator
;; case delimiter
& background commands
( ) command grouping
< input redirection
<< input from a here document
> output creation
>> output append
b) patterns
* match any character(s) including none
? match any single character
[...] match any of the enclosed characters
c) substitution
${...}substitute shell variable
`...` substitute command output
d) quoting
\ quote the next character
'...' quote the enclosed characters except for '
"..." quote the enclosed characters except for $ ` \ "
for while until do done
{ }
Man(1) output converted with
man2html