views:

1268

answers:

3

I've found a great little program that will allow me to add user friendly GUI's to my Bash Scripts;

whiptail

However the whiptail man page isn't all that helpful and doesn't provide any examples. After doing some google searches I understand how to create a simple yes/no menu using whiptail:

#! /bin/bash
# http://archives.seul.org/seul/project/Feb-1998/msg00069.html
if (whiptail --title "PPP Configuration" --backtitle "Welcome to SEUL" --yesno "
Do you want to configure your PPP connection?"  10 40 )
then 
        echo -e "\nWell, you better get busy!\n"
elif    (whiptail --title "PPP Configuration" --backtitle "Welcome to
SEUL" --yesno "           Are you sure?" 7 40)
        then
                echo -e "\nGood, because I can't do that yet!\n"
        else
                echo -e "\nToo bad, I can't do that yet\n"
fi

But what I would really like to build a file select menu using whiptail to replace some old code I have in a few different backup/restore bash scripts I have:

#!/bin/bash
#This script allows you to select a file ending in the .tgz extension (in the current directory)
echo "Please Select the RESTORE FILE you would like to restore: "
   select RESTOREFILE in *.tgz; do
   break #Nothing
   done
echo "The Restore File you selected was: ${RESTOREFILE}"

I assume this has to be done via the '--menu' option of whiptail, but I am not sure how to go about it? Any pointers? Or can you point me in the direction of some whiptail examples?

+1  A: 

Whiptail is a lightweight reimplementation of the most popular features of dialog, using the Newt library. I did a quick check, and many features in Whiptail seem to behave like their counterparts in dialog. So, a dialog tutorial should get you started. You can find one here but Google is your friend of course. On the other hand, the extended example probably contains a lot of inspiration for your problem.

fvu
A: 

I've tried following, which worked:

whiptail --title "PPP Config" --backtitle "Welcome to SEUL" --menu YourTitle 20 80 10 `for x in $(ls -1 *.tgz); do echo $x "-"; done`

you might change this into a multiple-liner as well, i've added checking for empty list:

MYLIST=`for x in $(ls -1 *.tgz); do echo $x "-"; done`
WC=`echo $MYLIST | wc -l`

if [[WC -ne 0]]; then
    whiptail --title "PPP Config" --backtitle "Welcome to SEUL" --menu YourTitle 20 80 10 $MYLIST
fi

you need to adjust the numbers in order to get a cleaninterface. And you may replace the "-" by anything else if you want to. But if you don't, you will see 2 entries per line.

By the way: The selected entry is printed onto stderr.

This could need some more improving, but for a basic idea I think it's enough.

Atmocreations
+2  A: 

Build an array of file names and menu select tags:

i=0
s=65    # decimal ASCII "A" 
for f in *.tgz
do
    # convert to octal then ASCII character for selection tag
    files[i]=$(echo -en "\0$(( $1 / 64 * 100 + $1 % 64 / 8 * 10 + $1 % 8 ))")
    files[i+1]="$f"    # save file name
    ((i+=2))
    ((s++))
done

A method like this will work even if there are filenames with spaces. If the number of files is large, you may have to devise another tag strategy.

Using alpha characters for the tags lets you press a letter to jump to the item. Numeric tags don't seem to do that. If you don't need that behavior, then you can eliminate some complexity.

Display the menu:

whiptail --backtitle "Welcome to SEUL" --title "Restore Files" \
    --menu "Please select the file to restore" 14 40 6 "${files[@]}"

If the exit code is 255, the dialog was canceled.

if [[ $? == 255 ]]
then
    do cancel stuff
fi

To catch the selection in a variable, use this structure (substitute your whiptail command for "whiptail-command"):

result=$(whiptail-command 2>&1 >/dev/tty)

Or

result=$(whiptail-command 3>&2 2>&1 1>&3-)

The variable $result will contain a letter of the alphabet that corresponds to a file in the array. Unfortunately, Bash prior to version 4 doesn't support associative arrays. You can calculate the index into the array of the file from the letter like this (notice the "extra" single quote):

((index = 2 * ( $( printf "%d" "'$result" ) - 65 ) + 1 ))

Example:

Welcome to SEUL
                ┌──────────┤ Restore Files ├───────────┐
                │ Please select the file to restore    │
                │                                      │
                │            A one.tgz      ↑          │
                │            B two.tgz      ▮          │
                │            C three.tgz    ▒          │
                │            D another.tgz  ▒          │
                │            E more.tgz     ▒          │
                │            F sp ac es.tgz ↓          │
                │                                      │
                │                                      │
                │       <Ok>           <Cancel>        │
                │                                      │
                └──────────────────────────────────────┘
Dennis Williamson
Please note: I have edited my answer to replace the previous octal conversion formula which was (<s>almost</s>) completely wrong.
Dennis Williamson
For temporary files you can use mktemp. For example, <code>mytempfile=$(mktemp) ; echo "Hello world">$mytempfile; echo Contents of ${mytempfile}: $(cat $mytempfile) ; rm -f $mytempfile</code>
jbatista
@jbatista: That's true, but how is it applicable? There's no mention of temporary files here.
Dennis Williamson