Processing options

From FBSD_tips

Jump to: navigation, search

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.

Personal tools