TUI with whiptail
Introduction
Section titled “Introduction”Whiptail allows shell scripts to display dialog boxes. It aims to show information, or to get input from the user in a friendly way. Whiptail is included by default on Debian.
whiptail is a dialog replacement using newt instead of ncurses.
whiptail is designed to be drop-in compatible with dialog, but has fewer features: some dialog boxes are not implemented, such as tailbox, timebox, calendarbox, etc.
Note that there are also other dialog-compatible programs like xdialog (Displays X11 Windows) and zenity (aka gdialog, displays Gtk Windows).
Basic Dialog Boxes
Section titled “Basic Dialog Boxes”Info Box
Section titled “Info Box”#!/bin/bash
TERM=ansi whiptail --title "Example Dialog" --infobox "This is an example of an info box." 8 60
# --title is displayed at the top of the dialog box.# 1st argument to --infobox is the dialog box text which is shown beneath the title.# next two arguments specify the height and width of the dialog box.
# There is a bug that makes the Info Box not display on some shells.# If this is the case you can set the terminal emulation to something different and it will work.# TERM=ansi whiptail # ...Important notes:
--titlevalue is displayed at the top of the dialog box.- 1st argument to
--infoboxis the dialog box text which is shown beneath the title. - Next two arguments specify the height and width of the dialog box.
Message Box
Section titled “Message Box”#!/bin/bash
whiptail --title "Example Dialog" --msgbox "This is an example of a message box. You must hit OK to continue." 8 60
# the last two arguments specify the height and width of the message box.# press Enter to exit the message boxLast two arguments specify the height and width of the message box.
Press Enter keyboard key to exit the message box.
Yes/No Box
Section titled “Yes/No Box”#!/bin/bash
whiptail --title "Example Dialog" --yesno "This is an example of a yes/no box." 8 60
# the last two arguments specify the height and width of the message box.# the return statement of the previous command is stored into $? variable# if the reply is Yes, then $? = 0# if the reply is No, then $? = 1
if [ $? -eq 0 ]; then # you can do whatever you want within this if statement, in this case a message box is displayed whiptail --title "Yes Dialog" --msgbox "User replied YES. You must hit OK to continue." 8 60else whiptail --title "No Dialog" --msgbox "User replied NO. You must hit OK to continue." 8 60fiImportant notes:
- return statement of the previous command, in bash, is stored into
$?variable - if the reply is Yes, then
$?is equal to0 - if the reply is No, then
$?is equal to1
Input Box
Section titled “Input Box”#!/bin/bash
COLOR=$(whiptail --inputbox "What is your favorite Color?" 8 40 "Blue" --title "Color Input Dialog" 3>&1 1>&2 2>&3)# trick to swap stdout and stderr.
# you can pack this inside if, but it seems really long for some 80-column terminal users.# save the return value into a variable
EXIT_STATUS=$?if [ $EXIT_STATUS = 0 ]; then whiptail --title "Color Dialog" --msgbox "User selected Ok and entered color = $COLOR" 8 60else whiptail --title "Color Dialog" --msgbox "User selected Cancel" 8 60fi
echo "# Exit status = $EXIT_STATUS"Please Note: 3>&1 1>&2 2>&3 trick creates a temporary file descriptor (called 3) to swap 1 (standard output) and 2 (standard error), allowing you to capture the output into a variable.
Text Box
Section titled “Text Box”#!/bin/bash
echo "Welcome to Bash $BASH_VERSION" > test_textbox
# arguments: filename height widthwhiptail --textbox test_textbox 12 80
# A text box with contents of the given file inside.# Add --scrolltext if the filename is longer than the window.
echo "APT list installed packages:\n"> long_textboxapt list | grep "installed" | head -n 20 | cut -d'/' -f1 >> long_textbox
whiptail --textbox --scrolltext long_textbox 12 80
# shows the first 20 APT packages installed on the machine# press the right key to move the "<Ok>" button and press Enter to exit the text-box
rm test_textbox long_textboxPress the right key to move the <Ok> button and press Enter to exit the text-box.
Password Box
Section titled “Password Box”#!/bin/bash
PASSWORD=$(whiptail --passwordbox "Please enter your secret password" 8 60 --title "password dialog" 3>&1 1>&2 2>&3)# trick to swap stdout and stderr.
# you can pack this inside if, but it seems really long for some 80-column terminal users.EXIT_STATUS=$?if [ $EXIT_STATUS == 0 ]; then whiptail --title "Password Dialog" --msgbox "User selected Ok and entered password = $PASSWORD" 8 60else whiptail --title "Password Dialog" --msgbox "User selected Cancel" 8 60fi
echo "# Exit status = $EXIT_STATUS"Menu Box
Section titled “Menu Box”#!/bin/bash
# utility tag names for menu and switch-caseTAG_1="(Option 1)"TAG_2="(Option 2)"TAG_3="(Option 3)"TAG_4="(Option 4)"
# menu should be used when you want the user to select one option from a list, such as for navigating a program.MENU_CHOOSE=$(whiptail --title "Menu Dialog" --menu "Choose an option" 16 60 8 \"$TAG_1" "Describe option 1." \"$TAG_2" "Describe option 2." \"$TAG_3" "Describe option 3." \"$TAG_4" "Describe option 4." \3>&1 1>&2 2>&3)
# values given to --menu are:# 1. text describing the menu ("Choose an option")# 2. height of the dialog (16)# 3. width of the dialog (60)# 4. height of the menu list (8)# The rest of the values are a list of menu options in the format `tag item`.# `tag` is the name of the option which is printed to `stderr` when selected, and `item` is the description of the menu option.
# you can then use a switch-case to perform different action based on the menu result
EXIT_STATUS=$?if [ $EXIT_STATUS == 0 ]; then MSG_BOX= case $MENU_CHOOSE in "$TAG_1") MSG_BOX="User selected Ok and entered option 1." ;; "$TAG_2") MSG_BOX="User selected Ok and entered option 2." ;; "$TAG_3") MSG_BOX="User selected Ok and entered option 3." ;; "$TAG_4") MSG_BOX="User selected Ok and entered option 4." ;; *) MSG_BOX="Some error occurs." ;; esac
whiptail --title "Menu Dialog" --msgbox "$MSG_BOX" 8 60else whiptail --title "Menu Dialog" --msgbox "User selected Cancel" 8 60fiValues given to --menu are:
- text describing the menu (
"Choose an option") - height of the dialog (
16) - width of the dialog (
60) - height of the menu list (
8)
The rest of the values are a list of menu options in the format tag item.
tag is the name of the option which is printed to stderr when selected, and item is the description of the menu option.
If you are presenting a very long menu and want to make best use of the available screen, you can calculate the best box size using this trick:
#!/bin/bash
eval_lines() { echo $(stty size | cut -d ' ' -f1)}
eval_columns() { echo $(stty size | cut -d ' ' -f2)}
show_menu() { local lines=$(eval_lines) local columns=$(eval_columns)
whiptail --title "Menu example" --menu "Choose an option" $(( $lines / 2 )) $(( $columns / 2 )) $(( $lines / 2 - 8 )) # ...}
# $lines and $columns variables represents the terminal lines and columnsChecklist Box
Section titled “Checklist Box”#!/bin/bash
# utility tag names for checklist and switch-caseTAG_1="(Option 1)"TAG_2="(Option 2)"TAG_3="(Option 3)"TAG_4="(Option 4)"
# check list allows a user to select one or more options from a list.CHECKLIST_CHOOSE=$(whiptail --title "Checklist Dialog" --checklist "Choose one or more options" 16 60 8 \"$TAG_1" "Describe option 1." ON \"$TAG_2" "Describe option 2." 1 \"$TAG_3" "Describe option 3." 0 \"$TAG_4" "Describe option 4." ON \3>&1 1>&2 2>&3)
# press Space-bar to select/unselect an item# press Enter to confirm the selection# press Esc to Cancel the selection
# values given to --checklist are:# 1. text describing the check list ("Choose one or more options")# 2. height of the dialog (16)# 3. width of the dialog (60)# 4. height of the menu list (8)# The rest of the values are a list of check list options in the format `tag item default_mode`.
# `default_mode` can be `ON` or `1` for the item to be marked as selected by default.# `default_mode` can be `OFF` or `0` for the item to be marked as unselected by default.
# when the user confirms their selections, a list of `tag` representing the choices is printed to `stderr`.
# ---# you can then use a switch-case to perform different action based on the check list result
EXIT_STATUS=$?
# echo "# EXIT_STATUS = $EXIT_STATUS"# echo "# CHECKLIST_CHOOSE = $CHECKLIST_CHOOSE"
# using regex to print all the user selection
if [ $EXIT_STATUS == 0 ]; then MSG_BOX="User selected Ok and entered: "
# check for each tag individually using regex [[ =~ ]] if [[ $CHECKLIST_CHOOSE =~ "$TAG_1" ]]; then MSG_BOX="$MSG_BOX\n- Option 1" fi
if [[ $CHECKLIST_CHOOSE =~ "$TAG_2" ]]; then MSG_BOX="$MSG_BOX\n- Option 2" fi
if [[ $CHECKLIST_CHOOSE =~ "$TAG_3" ]]; then MSG_BOX="$MSG_BOX\n- Option 3" fi
if [[ $CHECKLIST_CHOOSE =~ "$TAG_4" ]]; then MSG_BOX="$MSG_BOX\n- Option 4" fi
# handle case where nothing was selected but OK was pressed if [ -z "$CHECKLIST_CHOOSE" ]; then MSG_BOX="User selected Ok but chose no options." fi
whiptail --title "Checklist Dialog" --msgbox "$MSG_BOX" 16 60else whiptail --title "Checklist Dialog" --msgbox "User selected Cancel" 8 60fiImportant notes:
- press Spacebar to select/unselect an item
- press Enter to confirm the selection
- press Esc to Cancel the selection
Values given to --checklist are:
- text describing the menu (
"Choose one or more options") - height of the dialog (
16) - width of the dialog (
60) - height of the menu list (
8) - the rest of the values are a list of check list options in the format
tag item default_mode
default_mode can be ON or 1 for the item to be marked as selected by default.
default_mode can be OFF or 0 for the item to be marked as unselected by default.
When the user confirms their selections, a list of tag representing the choices is printed to stderr.
Radio List Box
Section titled “Radio List Box”#!/bin/bash
# utility tag names for radio list and switch-caseTAG_1="(Option 1)"TAG_2="(Option 2)"TAG_3="(Option 3)"TAG_4="(Option 4)"
# radio list is a dialog where the user can select one option from a list.# the difference between a radio list and a menu is that the user selects an option (using the space bar in whiptail) and then confirms that choice by hitting OK.
RADIOLIST_CHOOSE=$(whiptail --title "Radio List Dialog" --radiolist "Choose an option" 16 60 8 \"$TAG_1" "Describe option 1." 1 \"$TAG_2" "Describe option 2." 0 \"$TAG_3" "Describe option 3." 0 \"$TAG_4" "Describe option 4." 0 \3>&1 1>&2 2>&3)
# press Space-bar to select/unselect an item# press Enter to confirm the selection# press Esc to Cancel the selection
# values given to --radiolist are:# 1. text describing the radio list ("Choose an option")# 2. height of the dialog (16)# 3. width of the dialog (60)# 4. height of the radio list (8)# The rest of the values are a list of radio list options in the format `tag item`.# `tag` is the name of the option which is printed to `stderr` when selected, and `item` is the description of the radio list option.
# if you are presenting a very long radio list and want to make best use of the available screen, you can calculate the best box size by.# eval `resize`# whiptail --title "Menu example" --radiolist "Choose an option" $LINES $COLUMNS $(( $LINES - 8 )) ...
# ---# you can then use a switch-case to perform different action based on the radio list result
EXIT_STATUS=$?if [ $EXIT_STATUS == 0 ]; then MSG_BOX= case $RADIOLIST_CHOOSE in "$TAG_1") MSG_BOX="User selected Ok and entered option 1." ;; "$TAG_2") MSG_BOX="User selected Ok and entered option 2." ;; "$TAG_3") MSG_BOX="User selected Ok and entered option 3." ;; "$TAG_4") MSG_BOX="User selected Ok and entered option 4." ;; *) MSG_BOX="Some error occurs." ;; esac
whiptail --title "Radio List Dialog" --msgbox "$MSG_BOX" 8 60else whiptail --title "Radio List Dialog" --msgbox "User selected Cancel" 8 60fiValues given to --checklist are:
- text describing the menu (
"Choose one or more options") - height of the dialog (
16) - width of the dialog (
60) - height of the menu list (
8) - the rest of the values are a list of radio list options in the format
tag item.
tag is the name of the option which is printed to stderr when selected, and item is the description of the radio list option.
Progress Gauge
Section titled “Progress Gauge”#!/bin/bash
# syntax:# whiptail --gauge <text> <height> <width> [<percent>]
# also, gauge can read `percent` from `stdin` (standard input)function echo_progression() { for ((i = 0 ; i <= 100 ; i+=1)); do sleep 0.1 echo $i done}
echo_progression | whiptail --gauge "Waiting 0.1 sec from 0 to 100..." 8 60 0