Make Your Scripts User Friendly with Zenity
May 12th, 2008 by Mike Diehl in
The first time I played with Zenity, I recognized several potential uses for it. While I'm pretty comfortable with interacting with computers with a command line interface, I know many people are not. Zenity creates GUI widgets from a simple command line and can be used from any shell script. This allows an Administrator to write a shell script that performs a given function but make the program easy for less sophisticated users to interact with.
There are many times when you need to perform a repetitive task but you don't want to expose your users to the shell prompt. As much as I don't like having to point at things with a mouse in order to get a computer to do what I want, I understand that sometimes, using a GUI can reduce the chance of making a simple mistake. For example, if a program needs the user to enter a date, does it want the date in YYYY-MM-DD format, or MM-DD-YY format? Your program could tell the user how it expects the date,, but why make things more complicated than they need to be? Why not simply let the user select the date from an interface they are familiar with, a calendar? When was the last time you mistyped a long filename that that had mixed upper and lower case characters? Obviously, it would be easier to point and click on the filename instead.
With Zenity, your program can display calendar, file selection, text input and text message widgets. The results of the user's interaction with these widgets are then available to the shell script.
Let's take a look at a few simple examples before moving on to the real world example.
The following command will present the user with a calendar with “Example 1” in the title bar and the text, “When is your birthday?” at the top of the window. When the user selects a date, Zenity prints the selected date to STDOUT, which is then assigned to the variable, birthday.
export birthday=`zenity --calendar --text='When is your
birthday?' --title='Example 1'`

Users have learned what an error window means without even having to read the text and Zenity allows your scripts to give intuitive error indications. Simply use a command such as this.
zenity --error --text='Something very bad has happened!' --title='Example 2'

As you can see, Zenity is pretty easy to use. You simply tell it which widget you want it to display and then customize that widget using various other parameters. Then you can accept the results, if any, by reading Zenity's STDOUT.
Let's consider a hypothetical situation that arises quite often in business. You perform daily backups of your user's home directories and they frequently delete files and need you to recover them from backup. The problem is that you don't want to be bothered with simple tasks like that, but you don't want to have to train all your users to perform their own file recovery. Instead, like most Linux Administrators, you write a script.
Here is a quick script I wrote as an example of a backup file recovery program.
#!/bin/bash
export repository="/tmp/backups"
export user=`whoami`
############# Step 1 #########################
zenity --info --title="File Recovery Program" --text="You are about to be
asked for the date of the backup file you wish to recover from. Select the
date to continue."
############# Step 2 #########################
export date=`zenity --calendar --date-format=%Y-%m-%d`
if [ ! -f ${repository}/${user}/${date}.tgz ] ; then
echo No such file ${repository}/${user}/${date}.tgz
zenity --error --text="I\'m sorry, the backup for $date wasn\'t
found."
exit;
fi
############# Step 3 #########################
export files=`tar -tzf ${repository}/${user}/${date}.tgz |
zenity --list--title "Select the files to
recover" --column "Files" --separator=" " --multiple`
############# Step 4 #########################
zenity --info --title="File Recovery Program" --text="Next, you must select
which directory to recover your files to"
export target_dir=`zenity --file-selection --directory`
############# Step 5 #########################
zenity --info --title="File Recovery Program" --text="If you would like, I can
create a new directory for your recovered files to be saved to. If you would
like this, enter the name of the new directory next. Otherwise, just click on
OK"
export dir=`zenity --entry --title="File Recovery Program"`
############# Step 6 #########################
if [ -f ${target_dir}/${dir} ] ; then
zenity --error --text="I can not create a directory named
${target_dir}/
${dir} because there is a file with the same name already there"
exit
fi
if [ ! -d ${target_dir}/${dir} ] ; then
mkdir ${target_dir}/${dir}
fi
############# Step 7 #########################
tar -xzvf ${repository}/${user}/${date}.tgz -C ${target_dir}/${dir}/ $files |
zenity --progress –pulsate
zenity --info --title="File Recovery Program" --text="File recovery complete."
I've broken the script into 7 parts to make it easier to discuss what each part of the script does.
The script starts by defining a few important variables. Since this is a fictional scenario, I defined by backup repository to be in /tmp/backups; you'd probably put your backups elsewhere. Then we start step one of the user dialog.
Step one is pretty intuitive. It simply tells the user what to expect from the next dialog. When the user clicks on the OK button, we go to step tow and the user is presented with a calendar. The user picks the date from which to recover the lost files. The program line that displays the calendar uses a format string to tell Zenity how to format the resulting date. I wanted the date to be in a sortable format, so I chose YYYY-MM-DD. I replaced the default slash character with simple dashes because otherwise, the shell would think YYYY/MM/DD referred to 3 directory levels, when we really want it to mean a single filename. The format string is exactly like those used in date(1).
Step 2 then checks to see if the backup file actually exists. If it does not, then it displays an error message and terminates. Otherwise, we continue to the next step in the script.
In step 3, we send the output of the tar command to Zenity so that our user can select which files they want to restore from the tarball. We use the --multiple parameter so that they can select more than one file to recover. Also notice that we set the --separator to a single space. By doing this, we cause Zenity to produce a list of filenames for recovery and we can use that list as a single variable substitution on the command line.
Next we want to give the user the chance to restore their files to a directory other than their current working directory. We use the --file-selection widget for this purpose. By using the --directory parameter, we restrict the user to only being able to select directories, not files.
In step 5, we tell the user that the program can create a subdirectory in the directory they just selected and all of the recovered files will go into that subdirectory. Then we use the --enter widget to let the user tell us what subdirectory to create. If the user presses the OK button without entering anything, our script will simply restore the files into the selected directory.
In step 6, we do some error checking to make sure there isn't already a file with the same name as the subdirectory the user entered. If there is, we give the user an error message and our program terminates.
Then we make the subdirectory if it doesn't already exist.
Finally, in step 7, we recover the user's files from the selected tarball and place them in the appropriate directory, while giving the user visual feedback in the form of a progress bar. This way, our user doesn't need to guess if the program is working, and they aren't confronted with a list of filenames, or even worse, error messages.
As you can see, Zenity makes it very easy to write shell scripts that interact with the user via the GUI. Admittedly, this example was a little contrived. The example was meant to be rich enough to demonstrate as many of Zenity's features as possible while still appealing to practicality. It wouldn't take many changes to have the recover script use ssh and scp to access a remote backup repository, perhaps at a remote location. The user wouldn't have to know any of the details since all they ever see is a nice user-friendly series of dialog boxes.
Most Linux Administrators are comfortable with the command line interface and many might think that using Zenity to “dumb-up” a simple shell script is a waste of time. However many Linux Users aren't as proficient with the shell interface and will appreciate your efforts to make their work as “point and click” as possible.
__________________________
Mike Diehl is a freelance Computer Nerd specializing in Linux administration, programing, and VoIP. Mike lives in Albuquerque, NM. with his wife and 3 sons. He can be reached at mdiehl@diehlnet.com
Special Magazine Offer -- Free Gift with Subscription
Receive a free digital copy of Linux Journal's System Administration Special Edition as well as instant online access to current and past issues. CLICK HERE for offer
Linux Journal: delivering readers the advice and inspiration they need to get the most out of their Linux systems since 1994.
Subscribe now!
The Latest
Newsletter
Tech Tip Videos
- Jul-01-09
- Jun-29-09
Recently Popular
From the Magazine
July 2009, #183
News Flash: Linux Kernel 3.0 to include an on-the-go Expresso machine interface! Ok, maybe not, but Linux is definitely going mobile, from phones to e-readers. Find out more inside about Android, the Kindle 2, the Western Digital MyBook II, The Bug, and Indamixx (a portable recording studio). And if you've gone mobile and you been wanting more Emacs in your life then check out Conkeror.
To compliment the mobile we've got the stationary: parsing command line options with getopt, checking your Ruby code with metric_fu, and building a secure Squid proxy. How is this stationary you ask? What can we say? It's not. We just wanted to see if anybody actually read this part of the page :) .
All this and more, and all you have to do is get your hot sweaty hands on the latest copy of Linux Journal.
Delicious
Digg
StumbleUpon
Reddit
Facebook








Excellent Article
On July 1st, 2009 Akbar (not verified) says:
I am lovin' it :-)
Thank you for this great article.
getting a value from text box
On March 10th, 2009 Anonymous (not verified) says:
How can i get the value from a text box, if i need the name entered in text box inside my script.how can i get that.. also how to get the item selected in the case of radio selection and multi selection list..?
i will be thankful if i gets ur help..thanks!!
Is it me, or does Zenity lack the ability to show a bitmap?
On February 18th, 2009 Fernando Cassia (not verified) says:
I see no option in man zenity to show a bitmap. Would have made a great addition. Just show a bitmap (centered) with buttons below to make a choice.
If I'm wrong feel free to correct me.
Thanks,
FC
Exporting variables
On May 14th, 2008 Anonymous (not verified) says:
Why are you exporting the variables? There's surely no need for that?
Habit
On May 18th, 2008 Mike (not verified) says:
I usually set my variables in separate files which I then source as needed. I have to export them in that case and over the years it's just become a habit.
Lack of persistence
On May 13th, 2008 Donnie Berkholz (not verified) says:
I really love the idea of Zenity. My problem is that I can't write a serious, multistep app in it because it doesn't have persistent windows. The only way is to keep popping up new windows all the time, which is very hard to deal with.
It is a shame you can't use
On May 13th, 2008 Ryan Roth (not verified) says:
It is a shame you can't use glade with scripts like you can with python/
Who said you can't use Glade
On September 5th, 2008 Diego Torres Milano (not verified) says:
Who said you can't use Glade to design your interface ?
Take a look at autoglade.sf.net, it's an attempt to automate as much as possible the design and program of Gnome/GTK based, cross platform applications whose GUI is designed with Glade.
Links:
http://autoglade.wiki.sourceforge.net/autoglade+tutorial+-+first+steps
http://dtmilano.blogspot.com/2008/09/from-z-to.html
http://dtmilano.blogspot.com/2008/09/lists-meet-autoglade.html
http://dtmilano.blogspot.com/2008/08/introduction-this-article-will-guide.html
True indeed.
On July 9th, 2008 Anonymous (not verified) says:
True indeed.
Post new comment