Doing Arithmetic in Your Shell Script

Use $(( )) or let for integer arithmetic expressions.

COUNT=$((COUNT + 5 + MAX * 2))
let COUNT+=5+MAX*2

Branching on Conditions

if (( $# < 3 ))
then
    printf "%b" "Error. Not enough arguments.\n"
    printf "%b" "usage: myscript file1 op file2\n"
    exit 1
elif (( $# > 3 ))
then
    printf "%b" "Error. Too many arguments.\n"
    printf "%b" "usage: myscript file1 op file2\n"
    exit 2
else
    printf "%b" "Argument count correct. Proceeding...\n"
fi

Testing for File Characteristics

#!/usr/bin/env bash
# cookbook filename: checkfile
#
DIRPLACE=/tmp
INFILE=/home/yucca/amazing.data
OUTFILE=/home/yucca/more.results
if [ -d "$DIRPLACE" ]
then
    cd $DIRPLACE
    if [ -e "$INFILE" ]
    then
        if [ -w "$OUTFILE" ]
        then
            doscience < "$INFILE" >> "$OUTFILE"
        else
            echo "can not write to $OUTFILE"
        fi
    else
        echo "can not read from $INFILE"
    fi
else
    echo "can not cd into $DIRPLACE"
fi
Option Description
-b File is block special device (for files like /dev/hda1)
-c File is character special (for files like /dev/tty)
-d File is a directory
-e File exists
-f File is a regular file
-g File has its set-group-ID bit set
-h File is a symbolic link (same as -L)
-G File is owned by the effective group ID
-k File has its sticky bit set
-L File is a symbolic link (same as -h)
-O File is owned by the effective user ID
-p File is a named pipe
-r File is readable
-s File has a size greater than zero
-S File is a socket
-u File has its set-user-ID bit set
-w File is writable
-x File is executable

Testing for More Than One Thing

if [ -r $FILE -a -w $FILE ]

Testing for String Characteristics

#!/usr/bin/env bash
# cookbook filename: checkstr
#
# if statement
# test a string to see if it has any length
#
# use the command line argument
VAR="$1"
#
if [ "$VAR" ]
then
    echo has text
else
    echo zero length
fi
#
if [ -z "$VAR" ]
then
    echo zero length
else
    echo has text
fi

Testing for Equal

#!/usr/bin/env bash
# cookbook filename: strvsnum
#
# the old string vs. numeric comparison dilemma
#
VAR1=" 05 "
VAR2="5"
printf "%s" "do they -eq as equal? "
if [ "$VAR1" -eq "$VAR2" ]
then
    echo YES
else
    echo NO
fi
printf "%s" "do they = as equal? "
if [ "$VAR1" = "$VAR2" ]
then
    echo YES
else
    echo NO
fi
Numeric String Meaning
-lt < Less than
-le <= Less than or equal to
-gt > Greater than
-ge >= Greater than or equal to
-eq =,== Equal to
-ne != Not equal to

Looping for a While

Use the while looping construct for arithmetic conditions:

while (( COUNT < MAX ))
do
    some stuff
    let COUNT++
done

for filesystem-related conditions:

while [ -z "$LOCKFILE" ]
do
    some things
done

or for reading input:

while read lineoftext
do
    process $lineoftext
done

Looping with a Count

$ for (( i=0 ; i < 10 ; i++ )) ; do echo $i ; done

Looping with Floating-Point Values

for fp in $(seq 1.0 .01 1.1)
do
echo $fp
done

Branching Many Ways

case $FN in
*.gif) gif2png $FN
;;
*.png) pngOK $FN
;;
*.jpg) jpg2gif $FN
;;
*.tif | *.TIFF) tif2jpg $FN
;;
*) printf "File not supported: %s" $FN
;;
esac

Parsing Command-Line Arguments

LEN=72
CHAR='-'
while (( $# > 0 ))
do
case $1 in
    [0-9]*) LEN=$1
        printf $LEN
        ;;
    -c) shift;
        CHAR=${1:--}
        printf $CHAR
      ;;
    *) printf 'usage: %s [-c X] [#]\n' $(basename $0) >&2
        exit 2
    ;;
esac
shift
done

Creating Simple Menus

FILELIST=$(ls)
#Set it to a new value and you’ll get a new prompt.
PS3="0 inits >"
select file in $FILELIST
do
echo selected file:$file
done