The Linux Shells

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

Figure 1: Some UNIX/Linux Shells

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.

Common Features

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
$nnth argument (0...9)
$* All arguments
$? Exit status
# Begin comment

Figure 2: Common symbols

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

Figure 3: Common commands

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)

Figure 4: Common command syntax

Consult the Siever book for some one line examples.

The Bourne-again Shell

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/"

Figure 5: The day after 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 and Expressions

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

Figure 6: Hailstone program

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).

Conditional Statements

The usual set of conditional statements are available, as illustrated in Fugure 7.

if test-cmds
then
  cmd
  ...
fi
if test-cmds
then
  cmd
  ...
else
  cmd
  ...
fi
if test-cmds
then
  cmd
  ...
elif test-cmds
  cmd
  ...
else
  cmd
  ...
fi

Figure 7: Conditional statements

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
in
  regex)
    commands
    ;;
  ...
esac

Figure 8: Case statement

Note that to catch all remaining strings, use a * as the last regular expression.

Loops

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.

for var [ in list ]
do
  cmd
  ...
done
while test-cmds
do
  cmd
  ...
done
until test-cmds
do
  cmd
  ...
done

Figure 9: 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

Figure 10: Iterative Fibonacci sequence

This script assumes that the first command-line argument is the number of additional values in the sequence that are required.

Functions

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 $?"

Figure 11: Recursive factorial

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

Figure 12: Recursive Towers of Hanoi

The first command-line argument is the number of discs that we start with.

References

  1. Ellen Siever, Stephen Figgins & Aaron Weber, Linux in a Nutshell (fourth edition), O'Reilly & Associates, Inc., Sebastopol, CA, June 2003, ISBN 0-596-00482-6.


Last modified: Mon Dec 5 12:48:20 2005