Tuesday, December 29, 2009

Linux dialog utility short tutorial


dialog - display dialog boxes from shell scripts.

'dialog' is a utility for building console-based 'front ends' in UNIX like operating systems.
In this brief tutorial I am mentioning the usage of few important basic controls available with this 'dialog' utility and later I have created a very simple front end application in UNIX bash scripting using dialog.

To install 'dialog' on your ubuntu:

$ apt-get install dialog

Box options available with dialog: (Do a 'man' of dialog to know the usage of each control box)

--calendar
--checklist
--dselect
--editbox
--form
--fselect
--gauge
--infobox
--inputbox
--inputmenu
--menu
--mixedform
--mixedgauge
--msgbox
--passwordbox
--passwordform
--pause
--progressbox
--radiolist
--tailbox
--tailboxbg
--textbox
--timebox
--yesno

Checklist box:

A checklist box allows you to present a set of choices to the user and the user can toggle each one on or off individually using the space bar.
A sample one:

$ dialog --checklist "Choose OS:" 15 40 5 \
1 Linux off \
2 Solaris on \
3 'HP UX' off \
4 AIX off


Radiolist box:

The 'radiolist' control box is same as 'checklist' box.

$ dialog --backtitle "OS infomration" \
--radiolist "Select OS:" 10 40 3 \
1 "Linux 7.2" off \
2 "Solaris 9" on \
3 "HPUX 11i" off


Inputbox:

The 'inputbox' allows the user to enter a string.

$ dialog --title "Inputbox - Example" \
--backtitle "unstableme.blogspot.com" \
--inputbox "Enter your favourite OS here" 8 50


Menu box:

$ dialog --title "A dialog Menu Example" \
--menu "Please choose an option:" 15 55 5 \
1 "Add a record to DB" \
2 "Delete a record from DB" \
3 "Exit from this menu"

A message-box:

$ dialog --title "Example Dialog message box" \
--msgbox "\n Installation Completed on host7" 6 50


A yesno box:
    
$ dialog --title "Confirmation" --yesno "Want to quit?" 6 20


Infobox:

$ dialog --infobox "Processing, please wait" 3 34 ; sleep 5


Textbox:
It is a simple file viewer

$ dialog --textbox ~/work/conf.txt 10 4


From the sample application I have created at the end of this post, you will easily learn how to program these dialog boxes i.e. how to capture what user has entered/pressed. The dialog program writes its output to the standard error by default. In most of the dialog controls we redirect the choice user has selected to a tempfile and then process return value of dialog and contents of the tempfile.

Gauge Box:

#!/bin/sh
#A gauge Box example with dialog
(
c=10
while [ $c -ne 110 ]
do
echo $c
echo "###"
echo "$c %"
echo "###"
((c+=10))
sleep 1
done
) |
dialog --title "A Test Gauge With dialog" --gauge "Please wait ...." 10 60 0


Calendar Box:

#!/bin/sh

dat=$(dialog --stdout --title "My Calendar" \
--calendar "Select a date:" 0 0 25 12 2009)

case $? in
0)
echo "You have entered: $dat" ;;
1)
echo "You have pressed Cancel" ;;
255)
echo "Box closed" ;;
esac


Time Box:

#!/bin/sh

tim=$(dialog --stdout --title "A TimeBox" \
--timebox "Set the time:" 0 0 10 13 59)

case $? in
0)
echo "You have set: $tim" ;;
1)
echo "You have pressed Cancel" ;;
255)
echo "Box closed" ;;
esac



A sample application:

Suppose:

$ cat /home/user9/work/conf.txt
port:3322
threads:2
logdir:/opt/user6/logs/
confdir:/opt/user6/etc/

The following bash script using dialog utility will facilitate a simple interface to view or edit the content of the above config file.

#!/bin/sh
#http://unstableme.blogspot.com/
#A sample application using UNIX/Linux dialog utility
#Auto-size with height and width = 0 of the dialog controls

file='/home/user9/work/conf.txt'
tempfile1=/tmp/dialog_1_$$
tempfile2=/tmp/dialog_2_$$
tempfile3=/tmp/dialog_3_$$

trap "rm -f $tempfile1 $tempfile2 $tempfile3" 0 1 2 5 15

_edit () {
items=$(awk -F\: '{print $1,$2}' $file)
dialog --title "A Sample Application" \
--menu "What you want to change :" 0 0 0 $items 2> $tempfile1

retval=$?
parameter=$(cat $tempfile1)

[ $retval -eq 0 ] && tochange=$parameter || return 1

val=$(awk -F\: -v x=$tochange '$1==x {print $2}' $file)
dialog --clear --title "Inputbox - Test" \
--inputbox "Enter new value($tochange)" 0 0 $val 2> $tempfile2

dialog --title "Confirmation" --yesno "Commit ?" 0 0
case $? in
0) newval=$(cat $tempfile2)
awk -v x=$tochange -v n=$newval '
BEGIN {FS=OFS=":"}$1==x {$2=n} {print}
' $file > $file.tmp
mv $file.tmp $file
;;
1|255) dialog --infobox "No Changes done" 0 0
sleep 2
;;
esac
dialog --textbox $file 0 0
}

_main () {
dialog --title "A sample application" \
--menu "Please choose an option:" 15 55 5 \
1 "View the config file" \
2 "Edit config file" \
3 "Exit from this menu" 2> $tempfile3

retv=$?
choice=$(cat $tempfile3)
[ $retv -eq 1 -o $retv -eq 255 ] && exit

case $choice in
1) dialog --textbox $file 0 0
_main
;;
2) _edit
_main ;;
3) exit ;;
esac
}

_main

Dialog utility home page

26 comments:

Metalx1000 said...

one of the great things about "dialog" is that there is also "xdialog".

xdialog works just like dialog except it uses X to create the same dialog boxes as dialog but in GUI form.

So, it is very easy to write a script that checks if X is running and then substitutes xdialog for dialog is it is true. Making your program both terminal and X compatible.

Jadu Saikia said...

@MetalX100, ya that makes sense.
So we can have a function like this

-----------------
isRunning () {

local SERVICE=$1

if ps ax | grep -v grep | grep $SERVICE > /dev/null
then
return 0
else
return 1
fi
}

isRunning XY && DIALOG='Xdialog' || DIALOG='dialog'
-----------------

I am sure there must be better alternatives to the above check of 'X running status'; please suggest. Thanks for your comment.

Metalx1000 said...

There is probably better way then this (In fact I know I use to do it a different way, but I can't remember how I use to do it), but this is how I would do it.

--------------------------
#!/bin/bash

if [ -f /tmp/.X0-lock ]
then
Dialog=Xdialog
else
Dialog=dialog
fi


$Dialog --title "Example Dialog message box" \
--msgbox "\n Hello World!" 6 50
-------------------------------------

/tmp/.X0-lock is a file created by X and I believe it is removed when X is shutdown (Oh, it contains the PID for X if you ever want to kill X from a script).

I have not done a lot of testing on this method, but it should work.

Ari Hyttinen said...

About detecting if X is running, just check environment variable DISPLAY, ie. something like

DIALOG=dialog
test -n "$DISPLAY" && DIALOG=xdialog

This way it'll detect X correctly when connecting with ssh, and as a bonus it's trivial to disable xdialog (like for testing) with unset DISPLAY.

lnx said...

Another gauge demo:
---------------
#!/bin/bash
{ for I in 10 20 30 40 50 60 70 80 90 \
80 70 60 50 40 30 20 10 0; do
echo $I
sleep 1
done
echo; } | dialog --guage "A guage demo" 6 70 0
--------------

Anonymous said...

You should also check out zenity (GTK/GNOME):
http://library.gnome.org/users/zenity/stable/zenity-introduction.html.en

Metalx1000 said...

There are many dialog programs out there for Linux. Zenity is one of my favorites. It just has a nicer look then most the others. But, it's only for GUI I think, no terminal counter part like dialog.

tushar said...

could you please explain this line:
[ $retval -eq 0 ] && tochange=$parameter || return 1

Jadu Saikia said...

@tushar,

The meaning of :

[ $retval -eq 0 ] && tochange=$parameter || return 1

If retval is 0 (retval=$?, i.e retval contains the exit status of the previous command) then set 'tochange' to the content of the $parameter variable and if not 0 then return 1.


Assuming you have asked me for && and || :

# If you write "test && command", the command will only be executed if the test succeeds.
# If you write "test || command", the command will only be executed if the test fails.

Thanks for asking the question.

Linus said...

What you rarely find is a demonstration of several input fields on one dialog page. This works using --form:

dialog --backtitle "Network Interface Setup" \
--title "Network Configuration" \
--form "\nPlease enter the network configuration for eth0:" 11 55 3 \
"IP Address:" 1 1 "..." 1 16 16 15 \
"Network Mask:" 2 1 "255.255.255.0" 2 16 16 15 \
2> /tmp/setup-eth0.out

FORM=$(cat /tmp/setup-eth0.out | xargs)
for LINE in $FORM
do
echo $LINE
done

Jadu Saikia said...

@Linus, thanks a lot. Its useful.

Kory said...

I'm brand new to all this. I get how to create everything, but I can't find anywhere how to use the input data. Especially on the timebox. After they put in the time, then what? This may not be the place to ask but I can't find help anywhere else.

Metalx1000 said...

In the "time" example the time you enter is saved to a variable called $tim.

So, after you run dialog you can:
echo "$tim"

or save it to a file:
echo "$tim" > time.log

MikeAtVillage said...

Thanks, your short tutorial has been very useful. I've managed to create a dialog menu to select which of my servers to backup - using rsync.

Does anyone know how I can also use dialog to display the progress of my rsync, I'd like it to show each files as it's being copied - just so there's something to watch on the screen :-)

MikeAtVillage said...

Thanks, your short tutorial has been very useful. I've managed to create a dialog menu to select which of my servers to backup - using rsync.

Does anyone know how I can also use dialog to display the progress of my rsync, I'd like it to show each files as it's being copied - just so there's something to watch on the screen :-)

Ari Hyttinen said...

@MikeAtVillage: Check --gauge and --mixedgauge options (from man page or with Google). Here's a one-liner to get you started on experimenting:


(a=0; while [ $a -le 100 ]; do echo $a ; let a=a+10 ; sleep 1 ; done) | dialog --gauge foo 10 30


Understanding what happens inside parenthesis is not critical, you just want to replace it with something that outputs correct values for your purpose.

Jadu Saikia said...

@Ari, thanks for the solution.

Also I was wondering if we can make use of 'rsync -av --progress' option as well.

Ari Hyttinen said...

Jadu Saikia said: "Also I was wondering if we can make use of 'rsync -av --progress' option as well."

Unless rsync does something unusual, it'd probably be something like

rsync -av --progress | XXX | dialog --gauge 'rsync progress' 7 30

Where XXX is whatever is needed to process rsync output into percentage numbers, one per line. If rsync shows updates on separate lines, then one or two cuts and trs would probably do the trick in the most simple and "bashy" way. If it gets more complex, you might want to consider using perl or awk for processing, or just (while read line ; do ... ; done) if you want to use more plain shell script.

Note: If rsync updates a single line on screen, then tr "\\r" "\\n" can be used to convert that into multiple lines for easier handling (replace carriage returns with regular newlines).

MikeAtVillage said...

Thanks, I'll give it a try.

Guess-who-am-I said...

which rpm to dwnload for dialog nd xdialog to work ??

Jadu Saikia said...

@Guess-who-am-I , you can find the details here : http://www.icewalkers.com/rpm/dialog/fedora-core-6/download/dialog-1694.html

Which OS you are using ?

Sureshkumarchandrasekar said...

Hi Guys!

I am very much strucked here, i am using dialog in linux which pop up all kind of boxes in CLI mode, where as i could not find anything in solaris which is equivalent to dialog except Zenity, but zenity seems to work in GUI mode, how do i make it work in Command mode, displaying the box in terminal itself not in the desktop, for instance if iam connecting the server through putty im not able to access GUI. Please help!

Thanks in advance

Jadu Saikia said...

@Sureshkumarchandrasekar, thanks for the question. first of all, X server should be running on your UNIX(solaris) machine. Then you can have a X client (CygwinX or hummingbird exceed) installed on your local machine and you would need to export your DISPLAY variable (something like this : http://www.hungry.com/~jamie/xexport.html). Hope this helps.

Laércio Crestani said...

How to use a Gauge Box in a sudo command? Example:
make a progressbar to command: "sudo apt-get update" ?

Laércio Crestani said...

Hello! How do i use a Gauge box to a "sudo apt-get update" progress? Tanks

Robby Glasco said...

Can someone please provide an example of how to use --editbox in RHEL5? I'm trying to have a multi-line input for a system bulletin board.

Thanks!!!

© Jadu Saikia www.UNIXCL.com