Showing posts with label getopts. Show all posts
Showing posts with label getopts. Show all posts

Tuesday, April 1, 2008

Script For A Simple Menu Using Tput And ANSI Color

Simple Menu With An Option Selected

Click above to see a larger example of what happens when you dare to select option 1 ;)

Hey there,

Today I thought we'd look at something that almost all admins have to do at some point or another; create a simple shell menu script for users who aren't Unix or Linux savvy, but need to make use of the systems directly, nonetheless.

To spice it up (a little. There's only so much you can do ;) I've used colors within the standard shell menu framework, sticking with the ECMA compliant ANSI color codes. The reason I choose to stand by these color codes (since they, admittedly, lack the range of colors available in different flavors of Linux and Unix) is that they're virtually guaranteed to work on "all" flavors of Linux and Unix. Or maybe I'm just a people pleaser who hasn't realized that he can't win 'em all yet ;)

You'll notice also that, rather than just throw the menu together, using "case" inside a "select" loop, I went out of my way to complicate things by using tput to manage the cursor on the screen. In this case, it actually adds some functionality to the menu that would, otherwise, be impossible to implement. I shied away from unnecessarily using "getopts" when our "case" statement can handle these simple menu arguments just as efficiently :).

You can run this menu very simply, from the command line, like so:

host # ./SimpleMenu.sh

And there are only a few things to really take note of today. In a future post, I'll devote more time to utilizing your terminal screen with tput. It can be used to do a lot more useful, and entertaining, things than what we're having it do today.

Basically, in quick sequential order, we're using tput to:

1. Make the cursor invisible : tput civis
2. Position the cursor at various places on the terminal: tput cup x y <--- With x and y being single numeric coordinates designating the row and column, respectively.
3. Save the current cursor position: tput sc
4. Get back to (recover) the previously saved cursor position: tput rc
5. Make everything go back to the way it was, just in case our screen gets screwed up: tput reset

You can also, very simply, modify this shell menu script by just changing the menu options and adding your own routines to the case loop. And, if you can find something less offensive to your sensibilities, please do change the color scheme ;)

Enjoy :)


Creative Commons License


This work is licensed under a
Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License

#!/bin/bash
#
# SimpleMenu.sh - Only SomeWhat Useful ;)
#
# 2008 - Mike Golvach - eggi@comcast.net
# Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License
#

trap 'tput reset;exit 1' 1 2 3 9 15

tput civis

while :
do
echo -e "\033[44;37;22m"
clear
echo -e "\033[41;37"

echo -ne "\033[46;30m"
tput cup 8 25 ; echo -n "The Linux and Unix Menagerie"
tput cup 9 25 ; echo -n " Shell Account Services "
tput cup 10 25 ; echo -n " W E L C O M E "
echo -e "\033[40;32m"

tput cup 12 25 ; echo -n " 1. See Who's Logged In "
tput cup 13 25 ; echo -n " 2. Reboot The Server "
tput cup 14 25 ; echo -n " 3. Gain Root Access "
tput cup 15 25 ; echo -n " 4. Call Your Mother "
tput cup 16 25 ; echo -n " 5. Quit "

echo -ne "\033[41;30m"
tput cup 18 28 ; echo -n " Pick Your Poison: "
tput cup 18 48
tput sc

read y
tput cup 20 30

case "$y" in
1|S|s)
output=`w|awk '{print $1}' |xargs -ibing grep bing /etc/passwd|awk -F":" '{print $5}'`
starting_line=21
tput cup $starting_line 28;
echo -ne "\033[46;30mCurrently Logged In Users:"
echo -ne "\033[0m"
echo "$output"|while read x
do
let starting_line=$starting_line+1
tput cup $starting_line 28;
echo -n $x
done
tput rc
echo -n "Any Key To Menu"
read x
;;
2|R|r)
tput cup $starting_line 28;
echo -n "Option Not Active Yet"
tput rc
echo -n "Any Key To Menu"
read x
;;
3|G|g)
tput cup $starting_line 28;
echo -n "Option Not Active Yet"
tput rc
echo -n "Any Key To Menu"
read x
;;
4|C|c)
tput cup $starting_line 28;
echo -n "Option Not Active Yet"
tput rc
echo -n "Any Key To Menu"
read x
;;
5|Q|q)
tput reset
clear
exit
;;
*)
tput cup 20 28
echo "$y - Unknown Option"
tput rc
echo -n "Any Key To Menu"
read x
;;
esac
done

, Mike




Saturday, November 3, 2007

Using "case" Instead of "getopts" To Handle Script Input

Hey There,

I'm sure there are die-hard folks out there (like me), who prefer the getopts function to any other when it comes to parsing command line options for a nice shell script.

However, there are times when it makes more sense to use a "case" statement instead. One the most blatant examples can be seen in almost any init script on your Linux or Unix operating system. The simple rule is: If you're only accepting a very limited amount of input at the command line, there's no sense in over-complicating things. Not to mention the fact that "case" is more likely to port across systems and shells than getopts!

A "case" statement is very simple to write up. Let's take the example of the init script. It will generally accept about 3 arguments: start, stop or restart. Since these scripts are specifically for starting and stopping services, limiting to only those 3 command line options make sense and keeps the scripts brief, which is a benefit at boot-time.

Here's a sample "case" statement for a shell script that accepts the three above-mentioned arguments (only one of three, actually) and will return a usage error if it receives anything it doesn't expect:

case "$1" in
'start' )
/usr/local/bin/yourcommand start
;;
'stop' )
/usr/local/bin/yourcommand stop
;;
'restart' )
/usr/local/bin/yourcommand stop
/usr/local/bin/yourcommand start
;;
* )
echo "Usage: $0 [start|stop|restart]"
exit 1
;;
esac


Pretty simply, the "case" command iterates through the variable option it is told to act upon. Is this situation "$1" which translates, in the shell, to the first argument on the command line. It reads this in, translates it and then compares it to all of the available options it lists. Of course, it will match one of them, since our final option is "*" which is a special character which will match anything.

Note that the Usage output also utilizes a variable: $0. This equates to the name of the called command, exactly as it was called. So if you typed in "./myscript halt" you would get return output of: "Usage: ./myscript [stop|start|restart]" and be returned to the command line.

As you can see, in some cases (no pun intended) "case" makes a better case for utilization than getopts ;)

, Mike





Thursday, October 18, 2007

Dealing with Getopts OPTIND variable and the dreaded double-hyphen

Hey There,

As some scripters out there know, a really easy way to parse options to your shell script is to use the getopts function, especially if you have a lot of options to process.

OPTIND - the automatic variable set to represent the index of options (sometimes shifted and subtracted by 1) is generally used to determine whether you've run out of options to process once getopts is finished.

Of course ksh has the double-hypen (--), which, if you enter it as an argument to a script, means "stop processing arguments" and populates OPTIND, thus making checking whether its empty, a non-bullet-proof way of telling if someone has passed no arguments to your script.

Fortunately, it's pretty easy to get around by just setting a counter variable (this is necessary, because getopts never gets the -- and, therefore, can't process it; it's handled by the shell first... bummer)

Here's an example using opts_selected as the name of my tracking variable (usage, in this example is a reference to function in the script that just prints out a usage message and exits):

opts_selected=0

while getopts c:hmo: option
do
case $option in
c)
opts_selected=1
;;
h)
usage
;;
k)
opts_selected=1
;;
m)
opts_selected=1
;;
o)
opts_selected=1
;;
\?)
usage
;;
*)
usage
;;
esac
done
if [ $opts_selected -eq 0 ]
then
WhateverCodeYouWantToPutHere
fi


Now you can be sure you're script is definitely not being passed any arguments, including the double-hyphen, before you proceed to write the remainder!

, Mike