Whiptail and Dialog Snippets
Whiptail is a newt
-based utility allowing to build pseudo-graphical dialog boxes from shell scripts. Dialog uses ncurses
and is similar to whiptail
but has more options and, consequently, a bit harder to use. I find both useful when a user needs to be guided through a complex set of variables and to minimize fat-fingering.
The best to understand how to use dialog
and whiptail
(and sometimes you would want to use both of them in the same script) is by looking at some example. In this first example we’re prompting the user for database connection information to build the ${MYSQL}
connection string:
get_db_host() { db_host=$(whiptail --inputbox "Database host:" 8 78 "localhost" --title "Query Dialog" 3>&1 1>&2 2>&3) db_port=$(whiptail --inputbox "Database port:" 8 78 "3336" --title "Query Dialog" 3>&1 1>&2 2>&3) db_user=$(whiptail --inputbox "Database user:" 8 78 "sqlman" --title "Query Dialog" 3>&1 1>&2 2>&3) db_pass=$(whiptail --passwordbox "Database pass:" 8 78 "dbs1721" --title "Query Dialog" 3>&1 1>&2 2>&3) MYSQL="/usr/bin/mysql --batch --skip-column-names --max_allowed_packet=100M -h${db_host} --port=${db_port} -u${db_user} -p${db_pass} -e" }
The next example connects to the database to populate a whiptail
radio checklist with the names of available schemas. The second function connects to the selected database to get a list of tables and build another radio checklist. This is a good example of how to build dynamic menus.
get_db_name() { db_name=$(whiptail --title "Available Databases" --radiolist "Selects a database:" 30 78 20 \ `$MYSQL "show databases;" | sed 's/$/ DB OFF/g'` 3>&1 1>&2 2>&3) MYSQL="/usr/bin/mysql --batch --skip-column-names --max_allowed_packet=100M -h${db_host} --port=${db_port} -u${db_user} -p${db_pass} ${db_name} -e" } get_tbl_name() { tbl_name=$(whiptail --title "Available Tables in ${db_name}" --radiolist "Selects a table:" 30 78 20 \ `$MYSQL "show tables;" | sed 's/$/ TBL OFF/g'` 3>&1 1>&2 2>&3) }
The whiptail
utility has an unfortunate limitation: it can only ask you one question at a time. This can get tedious and distracting. The following example uses dialog
to present you with three questions and set variables var1
through var3
. The dialog
can’t assign each response to an individual variable. You would need to parse the output as illustrated below.
dialog_do() { # Clear variables var1 - var3 unset var{1..3} # Set default values var1="default value 1" var2="default value 2" var3="default value 3" # Launch dialog and gather user input exec 3>&1 dialog_values="$(dialog --ok-label "Submit" \ --clear \ --output-separator : \ --backtitle "Setting variables var1 - var7" \ --title "Some questions for you" \ --form "Answer this" \ 20 60 0 \ "Enter var1:" 1 1 "${var1}" 1 16 25 0 \ "Enter var2:" 2 1 "${var2}" 2 16 25 0 \ "Enter var3:" 3 1 "${var3}" 3 16 25 0 \ 2>&1 1>&3)" exec 3>&- clear # Now we parse the input assigned to colon-separated ${dialog_values} and set # individual variables for i in {1..3}; do eval "$(echo var${i})"="\"$(awk -F: -v i="${i}" '{print $i}' <<<${dialog_values})\"" done # And this is just to show that the variables have been set for i in {1..3}; do eval echo $(echo $`eval echo "var${i}"`) done }
And a few simple whiptail
dialog boxes that may come in handy in many scripts. This is a simple yes/no dialog:
if (whiptail --title "Continue/Exit" --yes-button "Continue" --no-button "Exit" --yesno "Proceed with the build?" 20 60); then echo "Continuing" fi
Here’s a simple message box. For some visual interest I added output of an array containing output of the ps
command:
IFS=$'\n'; a=($(ps -eLfw)); unset IFS whiptail --title "Simple message box" --msgbox "This is first line\n\nThis is second line\n\n$(for ((i = 0; i < ${#a[@]}; i++)) ; do echo "${a[$i]}" ; done | grep httpd)" 30 100
This is another message box designed to hold a bit more content:
whiptail --title "Scrollbox" --scrolltext --msgbox "$(tail -1000 /var/log/messages)" 30 100
Thank you for this excellent article. That’s just what I wanted to know.
Chris