Bourne Shell

Background

Functions

Built-in Commands:

Redirection:

Programming Language:

Sequences:

Variables:

Startup:

User-Defined Variables

Variables don’t have to be declared.

Example

#!/bin/sh
my_message="Hello World"
echo $my_message

read

Lets you take input from stdin.

Example

#!/bin/sh
echo What is your name?
read name
echo "Hello $name- hope you're well.”

export

Lets you export the variable for it to be inherited by another program.

Example:

$ source ./.profile

Curly Braces for Variables

Using curly braces for variables is a common convention in UNIX.

FormMeaning
${variable?word}Complain if undefined
${variable-word}Use new value if undefined
${variable+word}Opposite of the above
${variable=word}Use new value if undefined, and redefine

Note: An empty string ("") counts as null.

Example:

$ d=`expr $d+1`
$ d=`expr ${d-0}+1`

Undefine Variables

unset: Undefines variables.

Remember: The shell evaluates the variables and then operates on the results.

Special Variables

Note: Limited range of positional parameters

Example: Using shift to move positional parameters.

These two snippets assign the same positional variables to arg*:

arg1=$1;shift;
arg2=$1;shift;
arg3=$1;shift;
arg1=$1
arg2=$2
arg3=$3

Example: $*

#!/bin/sh
# usage: shift.sh `date`
echo $*;shift;
echo $*;shift;
echo $*;shift;
$ ./shift.sh `date`
Mon Jan 8 07:26:57 PM PST 2024
Jan 8 07:26:57 PM PST 2024
8 07:26:57 PM PST 2024

Example: $#

#!/bin/sh
# usage: ./param_counter ...
echo "Number of arguments are $6"
$ ./param_counter.sh 1 2 3 4 5 6
Number of arguments are 6

Debugging Bourne Shell Scripts

-x: Flag for the Bourne shell that echoes every command being ran.

Ways to Turn it On:

  1. Inside the script you can use set -x and set x to toggle it in the script body.
  2. Inside the script you can add it to the shebang (e.g., #!/bin/sh -x)
  3. You can run add it at the command line (e.g., $ -x ./script.sh)

expr

Four Types of Operations expr Performs:

  1. Arithmetic
  2. Logical
  3. Relational
  4. String
OperatorTypeMeaning
+ArithmeticAddition
-ArithmeticSubtraction
*ArithmeticMultiplication
/ArithmeticDivision
%ArithmeticRemainder
=RelationalEqual to
>RelationalGreater Than
>=RelationalGreater Than or Equal to
<RelationalLess Than
<=RelationalLess than or Equal to
!=RelationalNot Equal to
|BooleanOr
&BooleanAnd
:StringMatch or substitute

Examples: Using expr

$ echo `expr 2 + 5`
7
$ echo `expr length "cat"`
3
$ echo `expr substr "donkey" 4 3`
key
$ echo `expr index "donkey" "key"`
4

Flow Control Statements

Control Structures:

Three Ways to Group Commands:

Example: Grouping commands

if list then list fi
if list then list else list fi
if list then list elif list then list fi
if list then list elif list then list elif list then list fi
if list then list elif list then list else list fi
if list then list elif list then list elif list else list fi
while list do list done
until list do list done

Example: Using case

#!/bin/sh
while read f
do
case $f in
  hello)
      echo English ;;
  howdy)
      echo American ;;
  gday)
      echo Australian ;;
  bonjour)
      echo French ;;
  "guten tag")
      echo German ;;
  *)
      echo Unknown Language: $f ;;
esac
done < myfile

More on test Expressions

Format: [ expression ]

test returns a zero exit code of the expression evaluates to true; a nonzero exit status otherwise.

Example

#!/bin/sh
a=10
b=20
if [ $a == $b ]
then
  echo "a is equal to b"
elif [ $a -gt $b ]
then
  echo "a is greater than b"
elif [ $a -lt $b ]
then
  echo "a is less than b"
else
  echo "None of the condition met”
fi

Functions

Use the function keyword, like so:

#!/bin/sh
function square {
    sq=`expr $1 \* $1`
    echo "Number to be squared is $1."
    echo "The result is $sq "
}
echo "Give me a number to square. "
read number
value_returned=`square $number`
echo $value_returned