saved from http://wolfram.schneider.org/bsd/7thEdManVol2/shell/shell.html 
An Introduction to the UNIX Shell 
S. R. Bourne 
ABSTRACT
The shell is a command programming language that provides an interface to the 
UNIXoperating system. Its features include control-flow primitives, 
parameter passing, variables and string substitution. Constructs such 
as while, if then else, case and for are available. Two-way 
communication is possible between the shell and commands. 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 commands 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. Commands 
can be read either from the terminal or from a file, which allows command 
procedures to be stored for later use. 
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 argument -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 process and 
waits for it to finish. A command may be run without waiting for it to 
finish. For example, 
  - 
  
 - cc pgm.c & 
 
calls the C compiler to compile the file 
pgm.c. The trailing & 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 
 
except that no file is 
used. Instead the two processes are connected by a pipe (see 
pipe (2)) and are run in parallel. 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 contain 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 example, 
  - 
  
 - 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 pair of 
    characters separated by a minus will match any character lexically between 
    the pair. 
 
 
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 consist 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 patterns. 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 preceded by a 
\ is quoted and loses its special meaning, if any. The 
\ is elided so that 
  - 
  
 - echo \\? 
 
will echo a single ?, and 
  - 
  
 - 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 mechanism is 
the most simple and is recommended for casual use. 
A third quoting mechanism using double quotes is also available that prevents 
interpretation of some but not all metacharacters. Discussion of the 
details is deferred to section 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 
mistyping 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 directory contains the file 
.profile then it is assumed to contain commands and is read by the shell 
before reading any commands from the terminal. 
1.9 Summary 
  - 
  
 - 
  
    - ls 
Print the names of files in the current directory. 
    
     - ls >file 
Put the output from ls into file. 
     - ls | wc -l 
Print the number of files in the 
    current directory. 
     - ls | grep old 
Print those file names containing 
    the string old. 
     - ls | grep old | wc -l 
Print the 
    number of files whose name contains the string old. 
     - cc pgm.c & 
Run cc in the background. 
   
 
2.0 Shell procedures 
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 interchangeably. 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 $* 
 
which simply prepends some arguments to 
those already given. 
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. Furthermore, 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 
 
The command 
  - 
  
 - 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 semicolon (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 executed. 
  - 
  
 - 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 patterns 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 <<\\# 
... 
# 
 
The document is 
presented without modification to grep. If parameter substitution is not 
required in a here document 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 example, 
  - 
  
 - 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 available 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 substituted. 
Except for $? the following are set initially by the shell. 
$? is set after executing each command. 
  - 
  
 - 
  
    - $?
    
 - The exit status (return code) of the last command executed as a decimal 
    string. Most commands return a zero exit status if they complete 
    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 
 
makes the current directory 
    /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 executed 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 independently of the 
    current directory. If the command 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 interpretation (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) for a 
complete specification. 
  - 
  
 - 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 determined 
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 parameters $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.) 
2.7 Control flow - if 
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 command 
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. Otherwise, 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 ) 
 
In the first command-list is simply executed. The second form 
executes command-list as a separate process. For example, 
  - 
  
 - (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 
syntax errors. It may be invoked without modifying the procedure 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 substitution 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 sections of 
the UNIX manual. It is called, for example, as 
  - 
  
 - 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 
  
[1-9]*) s=$i ;; 
-t) N=t ;; 
-n) N=n ;; 
-*) echo unknown flag 
  \\'$i\\' ;; 
*) 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 
3.0 Keyword parameters 
Shell variables may be given values by assignment or when a shell procedure 
is invoked. An argument to a shell procedure 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 parameters 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 keyword 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 variables 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 ... 
 
Subsequent attempts to set readonly 
variables are illegal. 
3.2 Parameter substitution 
If a shell parameter is not set then the null string is substituted 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, otherwise 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?} 
... 
 
Colon (:) is 
a command that is built in to the shell and does nothing once its arguments have 
been evaluated. If any of the variables user, acct or bin 
are not set then the shell will abandon execution of the procedure. 
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. 
  - 
  
 - 
  
    - for i in `ls -t`; do ... 
The variable i 
    is set to the names of files in time order, most recent first. 
     - 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 substitution, 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. 
  - 
  
 - 
  
    - parameter substitution, e.g. $user 
    
 - command substitution, e.g. `pwd` 
 
  
    - 
    
 - 
    
Only one evaluation occurs so that if, for example, the value of the 
    variable X is the string $y then 
    
      - 
      
 - echo $X 
 
will echo $y.  
  
  
    - 
    
 - 
    
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.  
  
  
    - 
    
 - 
    
Each word is then scanned for the file pattern characters *, ? and 
    [...] and an alphabetical list of file names is 
    generated to replace the word. Each such file name is a separate 
    argument. 
 
 
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 substitution occurs 
but file name generation and the interpretation 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. 
  - 
  
 - 
  metacharacter \ $ * ` " ' ' n n n n n t ` 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 example, 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 substitution. 
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. 
  - Input output redirection may fail. For example, if a file does 
  not exist or cannot be created. 
  
 - The command itself does not exist or cannot be executed. 
  
 - The command terminates abnormally, for example, with a "bus error" or 
  "memory fault". See Figure 2 below for a complete list of UNIX 
  signals. 
  
 - 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. 
  - Syntax errors. e.g., if ... then ... done 
  
 - 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. 
  
 - 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. 
3.6 Fault handling 
Shell procedures normally terminate when an interrupt is received from the 
terminal. The trap command is used if 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 
executing 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 example, 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 temporary file; 
otherwise it would be possible for the process to die without removing the 
file. 
Since there is no signal 0 in UNIX it is used by the shell to indicate the 
commands to be executed on exit from the shell procedure. 
A procedure may, itself, elect to ignore signals by specifying 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 creates a new 
process using the system call fork. The execution environment for the 
command includes input, output and the states of signals, and is established in 
the child process before the command is executed. The built-in command 
exec is used in the rare cases when no fork is required and simply 
replaces the shell with a new command. For example, 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 parameter 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 
  character 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. 
  
 - <&-
  
 - The standard input is closed. 
  
 - >&-
  
 - The standard output is closed. 
 
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 
background commands to terminate. For this reason the UNIX convention 
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. 
  - -s
  
 - If the -s flag is present or if no arguments remain then commands 
  are read from the standard input. Shell output is written to file 
  descriptor 2. 
  
 - -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 interpreters 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$ 
Appendix A - Grammar 
  - 
  
 - item: word 
input-output 
name = value 
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 
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 
  
digit: 0 1 2 3 4 5 6 7 8 9 
 
Appendix B - Meta-characters and Reserved Words 
a) syntactic 
  - 
  
 - 
  
    - |
    
 - 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 $ ` \ " 
    
    
 
 
e) reserved words 
  - 
  
 - if then else elif fi 
case in esac 
for while until do done 
{ 
  }