Processing options
From FBSD_tips
Contents |
[edit] Rationale
Everyone likes options. And other people have to run your shell scripts ... right? So putting options into your shell scripts will make everybody like you. Well that might be overselling it a bit but having the right option processing in your script can make it worlds more flexible. Here I will break down processing the options into 3 main phases for a very simple script.
[edit] Command line parsing
[edit] Read the string
First we will use the getopt to check the options, printing a helpful message if the exit code is not zero. The string 'nh:u:' mean that 'n' is an option, 'h' is an option with a parameter, as is 'u'. If the command line doesn't match these options, getopt will exit with a non zero exit code (which the "if [ $? -ne 0 ]" checks).
args=`getopt nh:u: $*` if [ $? -ne 0 ] then echo 'Usage: ...' echo '-h host to key' echo '-u usename to key on host' echo '-n no op' exit 2 fi set -- $args
[edit] Iterate the string
Next we will process the list that getopt processed in a for loop. Processing goes until we encounter the '--' end of list marker. For options with no arguments, we shift once (just the option), for option / argumanr pairs we shift twice.
for i
do
case "$i"
in
-n)
NOOP=YES
shift;;
-h)
HOST=$2
shift; shift;;
-u)
UNAME=$2
shift; shift;;
--)
shift
break;;
esac
done
[edit] Check the values
Finally, we will apply logic to the resulting values, e.g. bail if there is no hostname specified, set up defaults ...
if [ X${HOST} = X ]; then echo "HOST not set"; exit; else echo "HOST is $HOST"; fi
if [ X${UNAME} = X ]; then echo "using current login"; UNAME=${USER}; else echo "UNAME is ${UNAME}"; fi
[edit] Example runs
And a couple of runs :
# ./k_m.sh -h ffjghf -n HOST is ffjghf using current login # ./k_m.sh -h ffjghf -u blah HOST is ffjghf UNAME is blah # /k_m.sh -u blah HOST not set
[edit] Using Dialog() to make it more responsive
The dialog utility can be employed to make this basi shell script more functional and visually appealing. It will create and drive various prototypical input widgets and read the values from them when the user is done with them.
[edit] Check the values, prompt for missing ones
Replacing the options checking portion of the example script with this will add interactive full screen user prompts that help "bullet proof" the data input to the script.
if [ X${HOST} = X ]
then
dialog 2> temp_$$.txt --menu text 9 13 2 host1 "" host2 "" || exit
HOST=`cat temp_$$.txt`
fi
echo "HOST is $HOST"
if [ X${UNAME} = X ]
then
dialog --yesno "Use current login?" 5 15 yes || exit
UNAME=${USER}
fi
echo "UNAME = ${UNAME}"
The --menu function returns true/false on exit and writes the selection to stderr. I redirect stderr to a file, taking measures to ensure it is unique using the $$ (current process ID) shell variable in the file name. The read the contents of the file into a shaell variable.
The --yesno function returns true/false on exit.
[edit] Selecting files and paths
A powerful utility of dialog is to select file names and paths. This is done by creating data files with the find() utility and passing that file to dialog(). Here is an example :
#!/bin/sh
find . > dialog_$$.txt
dialog 2> temp_$$.txt --ftree dialog.txt / hello 40 80 34 || echo "No selection"
SEL=`cat temp_$$.txt`
echo ${SEL}
This script drives the file selection mechanism of Dialog(). The --ftree argument takes a file formatted as the product of Find().
[edit] Making dialog more consistant
The previous examples have used constant screen dimensions for demonstration purposes. While this is simple and expedient it is obvious that different terminals will have differing dimesions (especially in the day and age of the GUI). Here is a way you can adapt to this to maintain a nearly constant aspect ratio using the capabilities of the curses database and stty().
#!/bin/sh
ROWS=`stty -e | head -1 | awk '{print $4}'`
COLS=`stty -e | head -1 | awk '{print $6}'`
HT=`echo "scale=0; ${ROWS} * .8" | bc`
WD=`echo "scale=0; ${COLS} * .8" | bc`
MN=`echo "scale=0; ${HT} - 7 " | bc`
find . > dialog_$$.txt
dialog 2> temp_$$.txt --ftree dialog.txt / hello ${HT} ${WD} ${MN} || echo "No selection"
SEL=`cat temp_$$.txt`
echo ${SEL}
It uses bc to calculate dimension to always occupy 80% of the available screen.
