This is the last article of a series focused in Gnu Bash scripting. On the first article we’ve just created a simple script with commands, one after another. We also saw some variables use.
The second article covered some bash control structures. The third one covered redirections, pipes, and command substitution.
On this last (for now) one, I will show how to create user interfaces with dialog in our scripts.
The source can be downloaded for compile from here: https://invisible-island.net/dialog/. To install precompiled binaries your distro surely have a package named ‘dialog’ that you can install with the package tools.
The following options apply to every widget we can use on dialog. The ones listed here aren’t all of them, but the ones I use the most.
- --ascii-lines Rather than draw graphics lines around boxes, “+” and “-” in the same place.
- --title title Specifies a title string to be displayed at the top of the dialog box.
- --default-button string Set the preselected button in a widget. Normally the first button in each widget is the default.
- --default-item string Set the default item in a checklist, form or menu box.
- --no-lines Rather than draw lines around boxes, draw spaces in the same place.
- --no-shadow Suppress shadows that would be drawn to the right and bottom of each dialog box
- --backtitle backtitle Specifies a backtitle string to be displayed at the top of the screen.
- --stdout Direct output to the standard output. Useful to store the user choice or response in a variable
dialog --backtitle 'this is backtitle' --title 'Title' --infobox "This is just an infobox with some options settled" 0 0
would produce this output:
My suggestion for scripts with several screens is to add an alias with some general options so you don’t need to type (or copy) every time, like this:
alias dialog="dialog --backtitle 'this is backtitle' --title 'Title' --stdout" dialog --infobox "This is just an infobox" 0 0
It’s the example from above. The syntax is:
--infobox text height width
Where text is the text to display, and height and width are the size of the dialog box. You can use the output of a command for text with command substitution, i.e. --infobox "$(cat somefile.txt)". The size is expressed in characters, a value of 0 means automatic.
Typical query style box with “Yes” and “No” answer buttons. The syntax is:
--yesno text height width
We can use it on a if-then-else block with some code like this:
if dialog --yesno "continue?" 0 0 then echo "You choose to continue" some_command some_other_command else echo "no" fi
A scrolling list of choices with single entry selection. The syntax is:
--menu text height width menu-height tagX itemX tagY itemY
Each menu entry consists of a tag string and an item string. I think is great to combine with a case-esac block as in the next example:
case $(dialog --menu "A menu of choices " 0 0 0 a item\ 1 b item\ 2 c item\ 3 d item\ 4) in a) echo "Item A" some commands ;; b) echo "Item B" some other commands ;; *) echo other ;; esac
An input box is useful when you want to ask questions that require the user to input a string as the answer. The syntax is:
--inputbox text height width [init]
init is optional and can be used to set a default answer.
A checklist box is similar to a menu box: there are multiple entries presented in the form of a menu. But instead of choosing just one entry, each entry can be turned on or off. The syntax is:
--checklist text height width list-height tag item status
status can be on or off. We can work with the selected options with a for loop and a case block to evaluate the selected options. Example:
for i in $(dialog --checklist "A menu of choices " 0 0 0 a item\ 1 off b item\ 2 off c item\ 3 off ) do case $i in a) echo "item 1 selected" ;; b) echo "item 2 selected" ;; c) echo "item 3 selected" ;; esac done
An alternative is radiolist where the user can choose just one item.
A typical progress bar. The meter indicates the percentage. New percentages are read from standard input, one integer per line. The syntax is:
--gauge text height width [percent]
Percent is optional an represent the initial percent done. This can be used with pipes. For example:
seq 1 100|dialog --gauge "A gauge" 0 0
A calendar box displays month, day and year. The syntax is:
--calendar text height width day month year
If the values for day, month or year are missing or negative, the current date are used.
Where to go from here
I’ve just showed a few of the available widgets (there are more than twenty). The dialog manpage gives help for all of them.
Of course, dialog isn’t the only available tool to create text user interfaces. There are alternatives like Xdialog, Whiptail (both mentioned on the dialog manpage) or Zenity. Remember that there’s more than one way to do it.
This four articles series on bash scripting is far far far away to be complete. My intention is to make you feel curious enough to investigate by yourself. Keep in hand the bash manpage (that can be confusing sometimes, at least to me). And keep closer to you the Advanced Bash Scripting Guide for a more comprehensive guide, full of examples.