#!/bin/sh


VERSION=0.2.4           # version of this script

PATH=/bin/:/usr/bin     # set a safe path
LOCK=/tmp/blah_lock.$$  # $$ is the PID of the shell

touch $LOCK             # create a 'lock'


#-----------------------------------------------------------------------------
# This subroutine prints to standard output (cat -) everything until 'EOF' is
# found.  It also removes the 'lock' file and exits with a return code of 1.
# The purpose of this subroutine is simply to describe the program to the
# person running it, and to show a synopsis and example of how to use it.
#
usage()
{
    cat - << EOF
This program does nothing functionally useful; however, its source code
is an example of a number of sh programming constructs.
    usage:   $0 [-h|--help] [--version] [-vd] [-n num] word file
    example: $0 alex /etc/group
EOF
    rm -f $LOCK
    exit 1
}


#-----------------------------------------------------------------------------
# This subroutine will prompt the operator whether to continue.  If something
# other then 'y' or 'Y' is entered, the program exits, making the "default"
# entry result in an exit.  Therefore if the operator presses Enter, the
# program will exit (the 'N' is capitalized to indicate this default
# behaviour).  If 'y' or 'Y' is pressed, the program prints a statement and
# continues execution.
#
ask_to_continue()
{
    echo -n "Do you want to continue ? [y|N] "
    read CONTINUE
    if [ "x${CONTINUE}" != "xy" ] && [ "x${CONTINUE}" != "xY" ] ; then
        echo "You chose to abort." ; rm -f $LOCK ; exit 1
    else
        echo "Continuing..."
    fi
}


#-----------------------------------------------------------------------------
# This subroutine will prompt the operator to continue execution.  If something
# other then 'n' or 'y' is entered, the program continues to prompt the user
# until one of the two keys is entered.  If 'n' is entered, the program exits.
# If 'y' is entered, the program prints a statement and continues execution.
#
ask_to_continue_2()
{
    echo -n "Do you want to continue ? [y|n] "
    read CONTINUE
    if [ "x${CONTINUE}" != "xy" ] && [ "x${CONTINUE}" != "xn" ] ; then
        echo "You have made an incorrect entry; next time enter 'y' or 'n'."
        ask_to_continue_2
    elif [ "x${CONTINUE}" = "xn" ] ; then
        echo "You chose to abort."
        rm -f $LOCK
        exit 1
    else
        echo "Continuing..."
    fi
}


#-----------------------------------------------------------------------------
#
# Process the command line options (manually, without the getopts command).
#
# Study this method and the one below, and you will see that this method is
# not as easy and reliable as the one below (despite its shortness)...
# that's why I've commented it out.
#
#while [ $# != 0 ] ; do
#    case $1 in
#        '-h') usage;;
#        '-v') VERBOSE=1; echo "VERBOSE mode is ON" ;;
#        '-d') DEBUG=1;   echo "DEBUG mode is ON" ;;
#        '-n') NUMBER=$2; echo "NUMBER is $NUMBER"; shift ;;
#        '--version') echo "Version $VERSION" ;;
#        '--help') usage ;;
#        * ) break ;;
#    esac
#    shift
#done


#-----------------------------------------------------------------------------
#
# Process the command line options (using getopts).
#
# The internal getopts command takes two parameters: a series of letters
# representing options to expect, and a variable name which is set to the
# parsed option on each call to getopts.  To indicate that an option takes
# an argument it should be followed by a colon.  A hypen is also allowed
# as a possible option.
#
# At each call to getopts, the index of the next argument is placed into the
# shell variable OPTIND.  When an option that takes an argument is parsed,
# the next positional parameter is assumed to be its argument, and is placed
# into the shell variable OPTARG.
#
# In the code below, when an option is parsed, $opt is set to that option.
# So if '-v' is parsed, $opt evaluates to 'v'.  The case command will match
# the 'v' and execute everything until ';;' is encountered.
#
# The way the hyphen is used below, it allows options such as '--version'.
#
# After the while loop has completed, it is important to execute the shift
# command as it is written below.  It does positional parameter shuffling
# which allows the program to continue as expected by moving (shifting) the
# options out of the way, so that the command line arguments can be processed.
#
while getopts "hvdn:-:" opt ; do
    case $opt in
        h ) usage ;;
        v ) VERBOSE=1; echo "VERBOSE mode is ON" ;;
        d ) DEBUG=1;   echo "DEBUG mode is ON" ;;
        n ) NUMBER=$OPTARG; echo "NUMBER is $NUMBER" ;;
        - ) case $OPTARG in
                version ) echo "Version $VERSION" ;;
                help ) usage ;;
                * ) echo "An unexpected double-hyphen option was encountered."
                    echo; usage ;;
            esac ;;
        ? ) echo "An invalid option was encountered."; echo; usage ;;
        * ) echo "An unexpected error occured."; echo; usage ;;
    esac
done

# Use the second shift instead of the first if you have an old version of sh.
shift $(($OPTIND -1))
#shift `expr $OPTIND - 1`


#-----------------------------------------------------------------------------
#
# Check the number of command line arguments. 
#
if [ $# != 2 ] ; then
    echo "You've passed $# command line argument(s), while 2 are expected."
    usage
fi


#-----------------------------------------------------------------------------
#
# Display the arguments passed via the command line.
#
echo "Argument 1: $1"
echo "Argument 2: $2"


#-----------------------------------------------------------------------------
#
# A good example of how to prompt the operator whether to continue.
#
ask_to_continue


#
# Another example of how to prompt to continue; however this one is less
# friendly because it does not assume a default, and it is too persistent.
#
ask_to_continue_2


#-----------------------------------------------------------------------------
#
# An example of grouping commands together...
# execute two separate echo commands and redirect the output of both to a file
#
{ echo -n "Hello, "; echo " World!"; } > $LOCK
{ echo "Appending a second line to the file."; } >> $LOCK
{ echo "Appending a third line to the file.";  } >> $LOCK


#-----------------------------------------------------------------------------
#
# Check the number of lines in the file.
#
# In this case, the file name is the value of the variable $LOCK.
#
if [ -r $LOCK ] ; then

    LINES=`wc -l $LOCK | awk '{print $1}'`

    if [ "x${LINES}" = "x1" ] ; then
        echo "The file named $LOCK contains ( 1 ) line."
    else
        echo "The file named $LOCK contains ( $LINES ) lines."
    fi
fi


#-----------------------------------------------------------------------------
# Generate a list of files, and redirect that list into a file.
# Ask the operator to enter a file name.  Check the entry for semi-validity.
# Compare the entered file name to the list of files in the current directory.
#
if [ -w $LOCK ] ; then

    #
    # Send a list of all files (one per line) in the current directory,
    # into the file named by the variable $LOCK.
    #
    ls -F . > $LOCK

    #
    # Prompt for a file name.
    #
    echo -n "Type the name of a file to create: "
    read NEWFILE

    #
    # Check validity of entry.
    # (Doesn't check for embedded spaces or potentially dangerous characters).
    #
    if [ -z $NEWFILE ] || [ ! -n $NEWFILE ] ; then
        echo "A file name must contain at least one non-space character."
        echo "Next time type something valid."
        rm -f $LOCK
        exit 2
    fi

    #
    # Run through the list of filenames, ignoring files starting with a period.
    #
    for FILENAME in `sed 's/^\..*$//' $LOCK | uniq` ; do

        if [ $DEBUG ] ; then
            echo "file: $FILENAME"
        fi

        if [ "x${FILENAME}" = "x${NEWFILE}" ] ; then
            echo -n "Sorry, $NEWFILE already exists."
            rm -f $LOCK
            exit 2
        fi  
    done

    echo "The file name you entered is unique: $NEWFILE"
fi


#-----------------------------------------------------------------------------
# An example of code that relies on perl to create a list of numbers
# which are then used by a 'for' loop to echo some text.  In a practical
# sense, the echo would be removed, resulting in the creation of a number
# of symbolic links.
#
for i in `perl -e '$i=0; print $i++ . " " while( $i<11 )'` ; do
    echo ln -s /home/u${i} /u${i}
done


#-----------------------------------------------------------------------------
echo "All done."
rm -f $LOCK


syntax highlighted by Code2HTML, v. 0.9.1