This chapter is based on Chapters 6 through 8 of the Siever book, Linux in a Nutshell [Siever 2003] .
Figure 1 illustrates some of the shells found on UNIX/Linux systems.
| Shell | Description |
|---|---|
bash | Bourne-again shell (GNU) |
csh | C shell (BSD) |
jsh | Job control shell (SVR4) |
ksh | Korn shell (Bell Labs) |
rc | Plan 9 shell (Bell Labs) |
rsh | Remote shell (TCP/IP) |
sh | Bourne shell (UNIX 7th Edition) |
tcsh | Popular extension of the C shell |
zsh | Popular extension of the Korn shell |
Standard GNU/Linux systems use bash as the
default shell. Some distributions, e.g. Red Hat Linux, have
/bin/sh as a symbolic link to
/bin/bash and /bin/csh as a
symbolic link to /bin/tcsh.
Figure 2 illustrates some features that are common to
both bash and tcsh.
| Symbol | Description |
|---|---|
> | Redirect output |
>> | Append output to a file |
< | Redirect input |
<< | Redirect input ("Here" document) |
| | Pipe output |
& | Run process in background |
; | Separate commands on one line |
* | Match character(s) in filename |
? | Match single character in filename |
!n | Repeat command number n |
[...] | Match any characters enclosed |
(...) | Execute commands in a subshell |
"..." | Quote allowing variable and command expansion |
'...' | Literal string |
`...` | Command substitution |
\ | Quote following character |
$var | Variable expansion |
$$ | Process ID |
$0 | Command name |
$n | nth argument (0...9) |
$* | All arguments |
$? | Exit status |
# | Begin comment |
In addition to these symbols, both shells have some common commands, as illustrated in Figure 3.
| Command | Description |
|---|---|
bg | Background execution |
break | Break out of a loop |
cd | Change directory |
continue | Resume a loop |
echo | Display output |
eval | Evaluate arguments |
exec | Execute a new program |
fg | Foreground execution |
jobs | Show active jobs |
kill | Terminate running job(s) |
shift | Shift positional parameters |
stop | Suspend a background job |
suspend | Suspend a foreground job |
umask | Set or list file permissions |
unset | Erase variable or function definition |
wait | Wait for a background job to finish |
There are too many differences for them to be listed here! Both shells can be used for writing scripts, similar to DOS batch files. Common command forms (syntax) are illustrated in Figure 4.
| Syntax | Description |
|---|---|
cmd & | Execute cmd in background |
cmd1 ; cmd2 | Command sequence |
(cmd1 ; cmd2) | Execute commands in a subshell |
cmd1 | cmd2 | Use output from cmd1 as input to cmd2 |
cmd1 `cmd2` | Use output from cmd2 as arguments to cmd1 |
cmd1 && cmd2 | Execute cmd2 only if cmd1 succeeds (AND) |
cmd1 || cmd2 | Execute cmd2 only if cmd1 fails (OR) |
Consult the Siever book for some one line examples.
bash is the GNU version of the standard Bourne
shell and incorporates popular features from other shells.
As such, it is a fully fuctional programming language and is
often employed for scripts as well as interactive use.
Figure 5 is a simple script that determines tomorrow from either the command-line argument or from today.
#!/bin/sh
# Determine tomorrow from $1 or, if missing, today
day=${1:-`date +%a`}
week='Sun Mon Tue Wed Thu Fri Sat Sun'
echo $week | sed "s/.*$day \([^ ]*\).*/\1/"
|
sed
The variable day is set to the value of the
first command-line argument but, if this is missing, the
current day is used, by taking the output from the
date command. This example makes heavy use of
regular expressions. The stream editor, sed,
matches the text up to the specified day (.*$day
), then "saves" tomorrow's text (\([^ ]*\)), and then
matches the remainder of the line (.*). The
complete line is replaced by the saved text
(\1) and printed. Nearly a typical one-liner!
Variables can contain either strings or integer values.
Figure 6 is the bash version of the well-known
Hailstone program.
#!/bin/sh
# Hailstone program
n=$1
while [ $n -gt 1 ]
do
if [ `expr $n % 2` -eq 0 ]
then
n=`expr $n / 2`
else
n=`expr 3 \* $n + 1`
fi
echo $n
done
|
The first assignment (n=$1) assigns the value
of the first command-line argument to the variable
n. Note that a dollar sign ($) is
used to interpolate the value of a variable. The second
assignment (n=`expr $n / 2`) uses the value of
an integer division operation. The third assignment
(n=`expr 3 \* $n + 1`) illustrates operator
precedence and also that it is necessary to escape the
special asterisk character (*) to prevent the
shell from using it (as a list of files in the current
directory).
The usual set of conditional statements are available, as illustrated in Fugure 7.
|
The test-cmds usually consists of a single test, although a series of commands is allowed. The case statement tests the value of a string against a regular expression. It proceeds down the list until one is found; the syntax is illustrated in Figure 8.
case string
|
Note that to catch all remaining strings, use a
* as the last regular expression.
The usual set of looping statements is available, although
the for loop is limited to processing a list of words. If
list is omitted, the positional
parameters ($@) are used. Figure 9 illustrates
the syntax of the looping statements.
|
A test can take one of two forms, either an expression
inside a pair of square braces, or the keyword
test followed by the expression. The first
form is used in these examples, as illustrated in Figure 10.
#!/bin/sh # Iterative Fibonacci sequence # last=0 this=1 tick=$1 while [ $tick -gt 0 ] do next=`expr $last + $this` echo $next last=$this this=$next tick=`expr $tick - 1` done |
This script assumes that the first command-line argument is the number of additional values in the sequence that are required.
Function arguments are called by value and referred to the
same way as positional parameters in a shell script
($1, $2, ..., $9).
Although only the first nine are available individually, the
remainder can be made accessible using the
shiftcommand. The well-known recursive
function for computing factorials is illustrated in Figure
11.
#!/bin/sh
# Recursive factorial
#
function fact
{
if [ $1 -eq 0 ]
then
return 1
fi
fact `expr $1 - 1`
return `expr $1 \* $?`
}
fact $1
echo "Factorial $1 is $?"
|
This is not a very good use of the exit status value! The final script illustrates the Towers of Hanoi game in Figure 12.
#!/bin/sh
# Towers of Hanoi
#
function hanoi
{
if [ $1 -eq 1 ]
then
echo "Move $2 to $3"
return
fi
hanoi `expr $1 - 1` $2 $4 $3
echo "Move $2 to $3"
hanoi `expr $1 - 1` $4 $3 $2
}
hanoi $1 left right middle
|
The first command-line argument is the number of discs that we start with.
| Last modified: Mon Dec 5 12:48:20 2005 |