21.2. Using tput

Now we have gone over the most common names of tput that you will probably use, let’s see how we can use tput in scripts.

21.2.1. Assigning tput commands

We can use the output of all tput names and store them inside more meaningful variable names. The format to do this is:


variable_name= `tput name` 

21.2.2. Using Boolean output

To use the Boolean tput output use the if statement:

STATUS_LINE=‘tput hs‘ 
if $STATUS_LINE; then 
  echo "your terminal has a status line" 
else 
  echo "your terminal has NO status line" 
fi

21.2.3. Using tput in your scripts

Here’s a script that has assigned the tput bel and cl to more meaningful variable names.

							$ pg tput1 
#!/bin/sh 
BELL=`tput bel` 
CLEAR=`tput cl` 

echo $BELL 
echo $CLEAR 

The following script changes a couple of video attributes and turns the cursor off and on:

							$ pg tput2 
#!/bin/sh 
BOLD=`tput bold` 
REV=`tput rev` 
NORMAL=`tput sgr0` 
CURSOR_OFF=`tput civis` 
CURSOR_ON=`tput cnorm` 
tput init 

#turn cursor off, highlight text, reverse some text, cursor on 
echo $CURSOR_OFF 
echo "${BOLD} WELCOME TO THE PIZZA PLACE${NORMAL}" 
echo -e "
${REV} WE ARE OPEN 7 DAYS A WEEK${NORMAL}" 
echo $CURSOR_ON 

21.2.4. Generating escape sequences

Please note that if you are using an emulator, you may have problems making the cursor invisible. This could be because:

  1. Some emulators do not trap the control character that makes the cursor invisible. I had to ask the author of the software emulator that I am using to make amendments to his source code so the cursor could be turned off.

  2. Some older versions of the tput civis command in my opinion do not seem to work properly.

The control character for turning the cursor off is ?25l (that’s the letter l). The character for turning it back on is ?25h.

All control characters start with an escape sequence, usually the escape key followed by [, then the actual sequence to turn some terminal attribute on or off.

You can use two different methods to generate escape sequences. The following table lists both methods depending on what system you have. The third method will work no matter what UNIX or LINUX variation you have got because the control sequence is embedded in the echo statement. This third method is the one we will use in the book.

To send an escape sequence to turn the cursor off:

LINUX/BSD echo -e "33[?25l"
System V echo "33[?25l"
Generic method echo "<CTRL-V><ESCAPE>[?25l"

The 33 is the value for the escape key. The ‘ ’ tells the echo command an octal value follows next. For instance to echo out the @ character, I could just use

echo "@"

or I could instead use the octal value of that character which is 100 to echo out the character.

echo -e "100"

For System V use

echo "100"

The results are the same.

The command clear clears the screen and sends the cursor to the top left-hand side of the screen, more commonly called home. The sequence it sends to do this on a VT terminal range is ESC[2J – you can send this sequence using an echo statement.

System V echo "33[2J"
LINUX/BSD echo -e "33[2J"

As with any control characters that are embedded in text files, do not try to cut and paste, as you will lose the characters’ special meaning. To insert control characters, for example, to turn on the cursor do this:


echo '<CTRL-V>hit the<ESCAPE>key then [?25h

That’s <CTRL-V>, then hit the escape key, then the characters [?25l

If your cursor does not go off when you issue a tput civis and you are sure it’s not the emulator, then use this little script to turn it on and off. I will leave it up to you to turn it into a function, or you could turn a couple of pages and find it already done.

							$ pg cursor 
#!/bin/sh 

# cursor on|off 
# turns the cursor on or off for the vt100, 200, 220, meth220 
# note : will work on normal tty connec.. if’ie on some win emulations 
# check TERM env for your type ! 
_OPT=$1 
if [ $# -ne 1 ]; then 
  echo "Usage:`basename $0` cursor [on|off]" 
  exit 1 
fi 

case "$_OPT" in 
on|ON|On) 
  # turn it on (cursor) 
  ON=`echo ^[[?25h` 
  echo $ON 
  ;; 
off|OFF|Off) 
  # turn it off (cursor) 
  OFF=`echo ^[[?25l` 
  echo $OFF 
  ;; 
;; 
*) echo "Usage: cursor on|off" 
  exit 1 
  ;; 
esac 

21.2.5. Cursor position

We can also use tput to place the cursor anywhere on the screen. The format for this is:


cup r c 

where r is the row (line) number down the screen and c is the column number across the screen.

It’s best to use this as a function, then you can pass it the row and column values.

xy() 
{
#_R= row, _C=column 
_R=$1 
_C=$2 
tput cup $_R $_C 
} 

clear 
xy 1 5 
echo -n "Enter your name :" 
read NAME 
xy 2 5 
echo -n "Enter your age :" 
read AGE

Of course it would be just as appropriate to pass it a string to display as well; here’s the slightly amended function that will do this.

xy() 
{
#_R= row, _C=column 
_R=$1 
_C=$2 
_TEXT=$3 
tput cup $_R $_C 
echo -n $_TEXT 
}

This could be called like this:

xy 5 10 "Enter your password :" 
read CODE

21.2.6. Centring text on the screen

It would not be too much trouble to centre text on the screen. All we need to do is get the columns from tput and then work out the length of the string supplied, take that value away from tput columns and divide the answer by two. All that is left is to supply the row number where we want the string to be displayed.

Here’s the piece of code that does the job. Only a slight change would be needed to read lines from a file and centre all the text on the screen.

Enter some characters, hit return and the text is displayed in the middle of screen at row 10.

echo -n "input string :" 
read STR 
# quick way of getting length of string 
LEN=`echo $STR | wc -c` 
COLS=`tput cols` 
NEW_COL=`expr ($COLS - $LEN ) / 2` 
xy 10 $NEW_COL 
echo $STR

For the above function to be more flexible you will probably want to call it with some text and a row number as well. This function will do that.

centertxt() 
{
_ROW=$1 
_STR=$2 
# quick way of getting length of string 
LEN=`echo $_STR | wc -c` 
COLS=`tput cols` 
_NEW_COL=`expr ($COLS -- $LEN ) / 2` 
xy $_ROW $_NEW_COL 
echo $_STR 
}

You could call the above function like this:

centertxt 15 "THE MAIN EVENT"

or like this, with the string as a argument:

centertxt 15 $1

21.2.7. Finding out your terminal attributes

Here’s a script that will interrogate terminfo via tput to display some terminal escape codes on some of the tput commands we have met.

							$ pg termput 
#!/bin/sh 
# termput 

#init tput for your terminal 
tput init 

clear 

echo " tput <> terminfo" 
infocmp -1 $TERM | while read LINE 
do 
  case $LINE in 
  bel*) echo "$LINE: sound the bell" ;; 
  blink*) echo "$LINE: begin blinking mode" ;; 
  bold*) echo "$LINE: make it bold" ;; 
  el*) echo "$LINE: clear to end of line" ;; 
  civis*) echo "$LINE: turn cursor off" ;; 
  cnorm*) echo "$LINE: turn cursor on " ;; 
  clear*) echo "$LINE: clear the screen ";; 
  kcuu1*) echo "$LINE: up arrow ";; 
  kcub1*) echo "$LINE: left arrow ";; 
  kcuf1*) echo "$LINE: right arrow ";; 
  kcud1*) echo "$LINE: down arrow ";; 
  esac 
done 

The command infocmp, extracts information about your terminal from the terminfo database. If you want to see the complete listing of your terminal definition file use the command:

$ infocmp $TERM

Here’s the output from my terminal using the termput script:

							$ termput 
tput <> terminfo 
bel=^G,: sound the bell 
blink=E[5m,: begin blinking mode 
bold=E[1m,: make it bold 
civis=E[?25l,: turn cursor off 
clear=E[HE[J,: clear the screen 
cnorm=E[?25h,: turn cursor on 
el=E[K,: clear to end of line 
el1=E[1K,: clear to end of line 
kcub1=E[D,: left arrow 
kcud1=E[B,: down arrow 
kcuf1=E[C,: right arrow 
kcuu1=E[A,: up arrow
						

21.2.8. Using function keys with your scripts

You can see what control sequence any of the special keys (F1, up arrow etc.) are sending by using the cat command. Type cat -v then press any control key to see what your terminal is sending down the line. When you have finished just press <CTRL-C> to quit.

In the following example cat is invoked. The keys pressed are F1 (^[OP), F2 (^[OQ) and the up arrow key (^[[A).

							$ cat -v 
^[OP^[OQ^[[A 
<CTRL-C>

Once you have this information you can then insert these characters into your scripts as additional methods of user selection.

The following script recognizes keys F1, F2 and the arrow keys. Your values may be different so use the cat command to see what values your terminal control keys send first.

							$ pg control_keys 
#!/bin/sh 
# control_keys 
# to insert use '<CTRL-V><ESCAPE>sequence' 
uparrowkey='^[[A' 
downarrowkey='^[[B' 
leftarrowkey='^[[D' 
rightarrowkey='^[[C' 
f1key='^[OP' 
f2key='^[OQ' 

echo -n " Press a control key then hit return" 
read KEY 

case $KEY in 
$uparrowkey) echo "UP Arrow" 
  ;; 
$downarrowkey) echo "DOWN arrow" 
  ;; 
$leftarrowkey) echo "LEFT arrow" 
  ;; 
$rightarrowkey) echo "RIGHT arrow" 
  ;; 
$f1key) echo "F1 key" 
  ;; 
$f2key) echo "F2 key" 
  ;; 
*) echo "unknown key $key" 
  ;; 
esac 

21.2.9. Using colours

Using colours on fields can make your data input screen look more professional. The colours we are going to use are ANSI standard. Not all colours work on all systems so here are the most common colours.

Foreground colours
Number Colour
30 black foreground
31 red foreground
32 green foreground
33 yellow (or brown) foreground
34 blue foreground
35 purple foreground
36 cyan foreground
37 white (or grey) foreground

Background colours
Number Colour
40 black background
41 red background
42 green background
43 yellow (or brown) background
44 cyan background
45 blue background
46 cyan background
47 white (or grey) background

The format to use for displaying background and foreground colours is:


<ESCAPE>[ background_number ; foreground_number m 

21.2.10. Generating colours

To generate a colour we will embed the control characters into the echo statement, because this method works on any system with a colour terminal. But again, as in control characters, you can generate colours using escape sequences inside an echo statement.

To generate a black background with a green foreground:

LINUX/BSD echo -e "33[40;32m"
System V echo "33[40;32m"
Generic method echo "<CTRL-V><ESCAPE>[40;32m"

For the generic method that’s <CTRL-V>, hit the <ESCAPE> key then [40;32m. The generic method is the one we will use in the book.

You will probably find it best to put your colour echo statements in a case statement then enclose it inside a function. Here’s my case colour function.

colour() 
{
# format is background;foregroundm 
case $1 in 
black_green) 
  echo '^[[40;32m' 
  ;; 
black_yellow) 
  echo '^[[40;33m' 
  ;; 
black_white) 
  echo '^[[40;37m' 
  ;; 
black_cyan) 
  echo '^[[40;36m' 
  ;; 
red_yellow) 
  echo '^[[41;32m' 
  ;; 
black_blue) 
  echo '^[[40;34m' 
  ;; 
esac 
}

To call the colours red_yellow (that’s a red background and yellow foreground) all I need to do is

colour red_yellow

To use colours in your scripts the action is this:


colour what_ever 
echo something 
# now change to a different colour 
colour what_ever 
echo something 

My terminal default screen colour is black and white, but I like using a black background on a green foreground. To fix this I simply insert an echo statement that generates this combination in my .profile file.

Figure 21.1 shows a basic input screen with some colours added to it. It looks a lot more interesting in colour!

Figure 21.1. A screenshot from the following script code using colours and the tput command


Here’s the code for the screen shown in Figure 21.1.

							$ pg colour_scr 
#!/bin/sh 
# colour_scr 
tput init 
MYDATE=`date +%D` 
colour() 
{
# format is background;foregroundm 
case $1 in 
black_green) 
  echo '^[[40;32m' 
  ;; 
black_yellow) 
  echo '^[[40;33m' 
  ;; 
black_white) 
  echo '^[[40;37m' 
  ;; 
black_cyan) 
  echo '^[[40;36m' 
  ;; 
black_red) 
  echo '^[[40;31m' 
  ;; 
esac 
} 

xy() 
#xy 
# to call: xy row, column, "text" 
# goto xy screen co-ordinates 
{
#_R= row, _C=column 
_R=$1 
_C=$2 
_TEXT=$3 
tput cup $_R $_C 
echo -n $_TEXT 
} 

center() 
{
# center 
# centers a string of text across screen 
# to call: center "string" row_number 
_STR=$1 
_ROW=$2 
# crude way of getting length of string 
LEN=`echo $_STR | wc -c` 

COLS=`tput cols` 
HOLD_COL=`expr $COLS - $LEN` 
NEW_COL=`expr $HOLD_COL / 2` 
tput cup $_ROW $NEW_COL 
echo -n $_STR 
} 

tput clear 
colour red_yellow 
xy 2 3 "USER: $LOGNAME" 
colour black_cyan 
center "ADD A NEW WARP DRIVE TO A STAR SHIP" 3 
echo -e "ff" 
center "___________________________________" 4 

colour black_yellow 
xy 5 1 "_________________________________________________________________" 
xy 7 1 "_________________________________________________________________" 
xy 21 1 "_________________________________________________________________" 
center "Star Date $MYDATE " 22 
xy 23 1 "_________________________________________________________________" 

colour black_green 
xy 6 6 "Initials :" 
read INIT 
xy 8 14 
echo -n "Security Code No: :" 
read CODE 
xy 10 14 
echo -n "Ship’s Serial No: :" 
read SERIAL 
xy 12 14 
echo -n "Is it on the Port Side :" 
read PORT 

colour red_yellow 
center " Save This Record [Y..N]: " 18 
read ans 

#reset to normal 
colour black_white 

As you can see, the script has no validation. That’s OK, because the aim of the script is to show you how to paint your screen.

21.2.11. Creating better menus

Remember the menu we created when we covered while loops? Let’s now improve on the menu script. The menu will now have the following options:


1 : ADD A RECORD 
2 : VIEW A RECORD 
3 : PAGE ALL RECORDS 
4 : CHANGE A RECORD 
5 : DELETE A RECORD 
P : PRINT ALL RECORDS 
H : Help screen 
Q : Exit Menu 

We will use our read_char function, so that the user does not have to hit return when selecting menu options. The trap command (more on traps later in the book) will also be used to ignore signals 2, 3 and 15. This will stop the user from trying to break out of the menu.

The menu will also have some form of control access. Certain privileged users will be able to change or delete records. The rest of the defined users will only be able to add, view or print records. A list of valid users with their access levels is held in a file called priv.user.

If a user tries to run the menu and their name is not present in the file, they will be informed that they cannot run this application and be exited.

For display purposes only, system commands will replace the actual behind the scenes options. Have a look at Chapter 22 if you want to see data validation on file updates.

Here’s the priv.user file that contains usernames of who can and cannot delete or change records. At a glance we can see that root, dave and matty cannot make changes to the database files, but peter and louise can.

							$ pg priv.user 
# prov.user access file for apps menu 
# edit this at your own risk !!!! 
# format is USER AMEND/DELETE records 
# example root yes means yes root can amend or delete recs 
#    "    dave no means no dave cannot amend or delete recs 
root no 
dave no 
peter yes 
louise yes 
matty no 

To check user accesses we first read the file in, ignoring comment lines and redirecting any other lines to a temp file.

user_level() 
{
while read LINE 
do 
  case $LINE in 
  #*);; 
  *) echo $LINE >>$HOLD1 
    ;; 
  esac 
done < $USER_LEVELS 

FOUND=false 
while read MENU_USER PRIV 
do 
  if [ "$MENU_USER" = "$USER" ]; 
  then 
    FOUND=true 
    case $PRIV in 
    yes|YES) 
      return 0 
      ;; 
    no|NO) 
      return 1 
      ;; 
    esac 
  else 
    continue 
  fi 
done <$HOLD1 
  if [ "$FOUND" = "false" ]; then 
  echo "Sorry $USER you have not been authorised to use this menu" 
  exit 1 
  fi 
}

The next step is to read in the newly formatted file. The variable FOUND is set to false. The temp file now holds just the names and privilege levels; variables are assigned to the user and privilege level. A test is carried out to see if the name in the file matches the USER; the value of USER is taken from the command whoami at the beginning of the script. If no match is found, the else comes into play and we continue with the next iteration of processing, using the command continue.

This process carries on until all names have been read in and compared. If after reading in the whole file no matches have been found, the test statement at the end of the code checks the variable FOUND. If it is set to false the user is kicked out.

If a match is found during the while loop, the variable FOUND is set to true. The case statement then traps the privilege levels and will either return 1 for normal level access or 0 for high level access.

When a user selects to either change or delete a record, a test is carried out based on the return code of the above function. In this example script the passwd file is sorted or a directory is listed

if user_level; then 
  sort /etc/passwd 
else 
  restrict 
fi

Restrict is a function that simply echoes out a violation prompt.

The above testing could have been done in one loop, but I think the code looks clearer using the two-file method, and it’s certainly a lot easier to debug.

Figure 21.2 shows user dave who has normal permission trying to change a record and is being prompted that he does not have the authorization to do so.

Figure 21.2. A screenshot of the menu with access restrictions


To exit the menu the user selects q or Q, and a function is called to clean up. When a user exits any large script, it’s a good idea to call a function to carry out this task. This allows for any growth in the commands you may want to run when a user exits, plus greater ease of readability of the code.

Here’s the script.

							$ pg menu2 
#!/bin/sh 
# menu2 
# MAIN MENU SCRIPT 
# ignore CTRL-C and QUIT interrupts 
trap "" 2 3 15 
MYDATE=`date +%d/%m/%Y` 
THIS_HOST=`hostname -s` 

USER=`whoami` 

# user level file 
USER_LEVELS=priv.user 

# hold file 
HOLD1=hold1.$$ 

# colour function 
colour() 
{
# format is background;foregroundm 
case $1 in 
black_green) 
  echo '^[[40;32m' 
  ;; 
black_yellow) 
  echo '^[[40;33m' 
  ;; 
black_white) 
  echo '^[[40;37m' 
  ;; 
black_cyan) 
  echo '^[[40;36m' 
  ;; 
red_yellow) 
  echo '^[[41;33m' 
  ;; 
esac 
} 

# just read a single key please 
get_char() 
{
# get_char 
# save current stty settings 
SAVEDSTTY=`stty -g` 
  stty cbreak 
  dd if=/dev/tty bs=1 count=1 2> /dev/null 
  stty -cbreak 
# restore stty 
stty $SAVEDSTTY 
} 

# turn the cursor on or off 
cursor() 
{
# cursor 
#turn cursor on/off 

_OPT=$1 
  case $_OPT in 
  on) echo '^[[?25h' 
    ;; 
  off) echo '^[[?25l' 
    ;; 
  *) return 1 
    ;; 
  esac 
} 

# check what privilege level the user has 
restrict() 
{
colour red_yellow 
echo -e -n "

07Sorry you are not authorised to use this function" 
colour black_green 
} 
user_level() 
{
# user_level 
# read in the priv.user file 
while read LINE 
do 
  case $LINE in 
  # ignore comments 
  #*);; 
  *) echo $LINE >>$HOLD1 
    ;; 
  esac 
done < $USER_LEVELS 

FOUND=false 
while read MENU_USER PRIV 
do 
  if [ "$MENU_USER" = "$USER" ]; 
  then 
    FOUND=true 
    case $PRIV in 
    yes|YES) 
      return 0 
      ;; 
    no|NO) 
      return 1 
      ;; 
    esac 
  else 
  # no match found read next record 
    continue 
  fi 
done <$HOLD1 
if [ "$FOUND" = "false" ]; then 
  echo "Sorry $USER you have not been authorised to use this menu" 
  exit 1 
fi 
} 

# called when user selects quit 
my_exit() 
{
# my_exit 
# called when user selects quit! 
colour black_white 
  cursor on 
  rm *.$$ 
  exit 0 
} 
tput init 
# display their user levels on the screen 
if user_level; then 
  ACCESS="Access Mode is High" 
else 
  ACCESS="Access Mode is Normal" 
fi 

tput init 
while : 
do 
tput clear 
colour black_green 
cat <<MAYDAY 
$ACCESS 
___________________________________________________________________ 
User: $USER        Host:$THIS_HOST                     Date:$MYDATE 
___________________________________________________________________ 
                 1 : ADD A RECORD 
                 2 : VIEW A RECORD 
                 3 : PAGE ALL RECORDS 
                 4 : CHANGE A RECORD 
                 5 : DELETE A RECORD 
                 P : PRINT ALL RECORDS 
                 H : Help screen 
                 Q : Exit Menu 
___________________________________________________________________ 
MAYDAY 
colour black_cyan 
echo -e -n "	Your Choice [1,2,3,4,5,P,H,Q] >" 
œread CHOICE 
CHOICE=`get_char` 
  case $CHOICE in 
  1) ls 
    ;; 
  2) vi 
    ;; 
  3) who 
    ;; 
  4) if user_level; then 
      ls -l |wc 
    else 
      restrict 
    fi 
    ;; 
  5) if user_level; then 
      sort /etc/passwd 
    else 
      restrict 
    fi 
    ;; 
  P|p) echo -e "

Printing records......." 
    ;; 
  H|h) 
  tput clear 
  cat <<MAYDAY 
  This is the help screen, nothing here yet to help you! 
  MAYDAY 
    ;; 
  Q|q) my_exit 
    ;; 
  *) echo -e "	07unknown user response" 
    ;; 
  esac 
echo -e -n "	Hit the return key to continue" 
read DUMMY 
done 

This type of menu could be called from a profile file with the exec command. The users would not be able to break out; they would be kept in the menu or the application(s) that the menu kicks off. This is fairly common practice for users who use only UNIX or LINUX applications and who are not bothered about the shell.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.149.236.69