How do I create a terminal-based GUI?

59,930

Solution 1

dialog --backtitle "Package configuration" \
       --title "Configuration sun-java-jre" \
       --yesno "\nBla bla bla...\n\nDo you accept?" 10 30

enter image description here

The user response is stored in the exit code, so can be printed as usual: echo $? (note that 0 means "yes", and 1 is "no" in the shell world).


Concerning other questions from the comment section:

  • to put into the dialog box the output from some command just use command substitution mechanism $(), eg:

     dialog --backtitle "$(echo abc)" --title "$(cat file)" ...
    
  • to give user multiple choices you can use --menu option instead of --yesno

  • to store the output of the user choice into variable one needs to use --stdout option or change output descriptor either via --output-fd or manually, e.g.:

    output=$(dialog --backtitle "Package configuration" \
                    --title "Configuration sun-java-jre" \
                    --menu "$(parted -l)" 15 40 4 1 "sda1" 2 "sda2" 3 "sda3" \
             3>&1 1>&2 2>&3 3>&-)
    echo "$output"
    

    This trick is needed because dialog by default outputs to stderr, not stdout.

And as always, man dialog is your friend.

Solution 2

The screenshot in the question looks like whiptail (a functionally-reduced program imitating dialog, using newt rather than ncurses). The way the title and buttons are rendered is built into each program, making them look different.

Here is a script which duplicates the original screenshot, for either whiptail or dialog:

#!/bin/sh
: ${DIALOG:=dialog}
case "$DIALOG" in
*dialog*)
        OPTS="$OPTS --cr-wrap"
        high=10
        ;;
*whiptail*)
        high=12
        ;;
esac
rows=$(stty size | cut -d' ' -f1)
[ -z "$rows" ] && rows=$high
[ $rows -gt $high ] && rows=$high
cols=$(stty size | cut -d' ' -f2)
$DIALOG --backtitle "Package configuration" \
       --title "Configuring sun-java6-jre" \
       $OPTS \
       --yesno '\nIn order to install this package, you must accept the license terms, the "Operating System Distributor License for Java" (DLJ), v1.1. Not accepting will cancel the installation.\n\nDo you accept the DLJ license terms?' $rows $((cols - 5))

and for comparison, screenshot with whiptail:

screenshot with whiptail

and with dialog:

screenshot with dialog

Besides the different appearance of the title and buttons, dialog uses different colors by default (though that is configurable—see screenshots), and it uses fewer lines on the screen.

dialog (and whiptail) use libraries for managing the display of lines, colors, etc. But you may also see newt used in Red Hat anaconda program as a shared library called from python (with the same appearance). Along the same lines, the kernel configuration program started as a (cut-down) copy of dialog, and then evolved into features using a shared library (without the original lxdialog program) much like the way newt is used from python.

From bash — you could use either dialog or whiptail for the most commonly-used features. Someone wrote a wrapper for those (in perl) to allow scripts to more readily use either those or a few others, but you're better off using dialog directly since the perl module is essentially common-denominator.

The dialog sources include examples of all of the widgets along with most of the command-line options:

cdialog (ComeOn Dialog!) version 1.3-20160424
Copyright 2000-2015,2016 Thomas E. Dickey
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

* Display dialog boxes from shell scripts *

Usage: cdialog <options> { --and-widget <options> }
where options are "common" options, followed by "box" options

Special options:
  [--create-rc "file"]
Common options:
  [--ascii-lines] [--aspect <ratio>] [--backtitle <backtitle>] [--beep]
  [--beep-after] [--begin <y> <x>] [--cancel-label <str>] [--clear]
  [--colors] [--column-separator <str>] [--cr-wrap] [--date-format <str>]
  [--default-button <str>] [--default-item <str>] [--defaultno]
  [--exit-label <str>] [--extra-button] [--extra-label <str>]
  [--help-button] [--help-label <str>] [--help-status] [--help-tags]
  [--hfile <str>] [--hline <str>] [--ignore] [--input-fd <fd>]
  [--insecure] [--item-help] [--keep-tite] [--keep-window] [--last-key]
  [--max-input <n>] [--no-cancel] [--no-collapse] [--no-cr-wrap]
  [--no-items] [--no-kill] [--no-label <str>] [--no-lines] [--no-mouse]
  [--no-nl-expand] [--no-ok] [--no-shadow] [--no-tags] [--nook]
  [--ok-label <str>] [--output-fd <fd>] [--output-separator <str>]
  [--print-maxsize] [--print-size] [--print-version] [--quoted]
  [--scrollbar] [--separate-output] [--separate-widget <str>] [--shadow]
  [--single-quoted] [--size-err] [--sleep <secs>] [--stderr] [--stdout]
  [--tab-correct] [--tab-len <n>] [--time-format <str>] [--timeout <secs>]
  [--title <title>] [--trace <file>] [--trim] [--version] [--visit-items]
  [--week-start <str>] [--yes-label <str>]
Box options:
  --buildlist    <text> <height> <width> <list-height> <tag1> <item1> <status1>...
  --calendar     <text> <height> <width> <day> <month> <year>
  --checklist    <text> <height> <width> <list height> <tag1> <item1> <status1>...
  --dselect      <directory> <height> <width>
  --editbox      <file> <height> <width>
  --form         <text> <height> <width> <form height> <label1> <l_y1> <l_x1> <item1> <i_y1> <i_x1> <flen1> <ilen1>...
  --fselect      <filepath> <height> <width>
  --gauge        <text> <height> <width> [<percent>]
  --infobox      <text> <height> <width>
  --inputbox     <text> <height> <width> [<init>]
  --inputmenu    <text> <height> <width> <menu height> <tag1> <item1>...
  --menu         <text> <height> <width> <menu height> <tag1> <item1>...
  --mixedform    <text> <height> <width> <form height> <label1> <l_y1> <l_x1> <item1> <i_y1> <i_x1> <flen1> <ilen1> <itype>...
  --mixedgauge   <text> <height> <width> <percent> <tag1> <item1>...
  --msgbox       <text> <height> <width>
  --passwordbox  <text> <height> <width> [<init>]
  --passwordform <text> <height> <width> <form height> <label1> <l_y1> <l_x1> <item1> <i_y1> <i_x1> <flen1> <ilen1>...
  --pause        <text> <height> <width> <seconds>
  --prgbox       <text> <command> <height> <width>
  --programbox   <text> <height> <width>
  --progressbox  <text> <height> <width>
  --radiolist    <text> <height> <width> <list height> <tag1> <item1> <status1>...
  --rangebox     <text> <height> <width> <min-value> <max-value> <default-value>
  --tailbox      <file> <height> <width>
  --tailboxbg    <file> <height> <width>
  --textbox      <file> <height> <width>
  --timebox      <text> <height> <width> <hour> <minute> <second>
  --treeview     <text> <height> <width> <list-height> <tag1> <item1> <status1> <depth1>...
  --yesno        <text> <height> <width>

Auto-size with height and width = 0. Maximize with height and width = -1.
Global-auto-size if also menu_height/list_height = 0.

Further reading:

Solution 3

I believe the package you are looking for is ncurses.

Wikipedia describes ncurses as follows:

ncurses (new curses) is a programming library providing an API that allows the programmer to write text-based user interfaces in a terminal-independent manner. It is a toolkit for developing "GUI-like" application software that runs under a terminal emulator

It is widely used, for example, in the menuconfig kernel configuration tool: Screen shot of Linux kernel menuconfig tool

Since you are using bash, you can use Bash Simple Curses (as mentioned by Runium in the comment below).

Share:
59,930

Related videos on Youtube

tempforFind Me In The Woods
Author by

tempforFind Me In The Woods

Updated on September 18, 2022

Comments

  • tempforFind Me In The Woods
    tempforFind Me In The Woods over 1 year

    I'm looking to create a terminal-based environment to adapt my Bash script into. I want it to look like this:

    Debian install

    • Pankaj Goyal
      Pankaj Goyal almost 8 years
      Look into dialog, which is what this appears to use.
    • user
      user almost 8 years
    • Admin
      Admin almost 8 years
      I think a terminal-based GUI is a TUI (which is different from CLI).
    • Bratchley
      Bratchley almost 8 years
      "tui" is a RH term IIRC. whiptail > dialog also
    • Peter Cordes
      Peter Cordes almost 8 years
      @Bratchley: GDB also uses tui for its split-window mode (showing registers, source, and commands with layout reg for example, and tui reg vec to show vector registers in the reg window (in a not-flexible way, so that part's not really useful :/). IDK if Redhat wrote the patch that added that feature, or even how old it is.
    • Peter Cordes
      Peter Cordes almost 8 years
      You could have checked what program was producing that output by using pstree or similar, to see the ultimate child process. Or see what processes have that specific tty open. That would narrow it down to a few, and you could then check their man pages to find that whiptail was doing it. There's probably a way to find what process is in the foreground on a given terminal, but I don't know it.
  • Runium
    Runium almost 8 years
    ncurses is a C-library. (If I understand correctly) OP wants a scripting environment (for bash). menuconfig is written in C. As an alternative to dialog, as per other answer, you could perhaps mention Bash Simple Curses which is written in bash (relying on tput).
  • tempforFind Me In The Woods
    tempforFind Me In The Woods almost 8 years
    thats beautiful "Bla bla bla..." but how do you capture the output?
  • jimmij
    jimmij almost 8 years
    @tempforFindMeInTheWoods if by output you mean exit code, then just as usuall: it is stored inside ? variable, try echo $?.
  • tempforFind Me In The Woods
    tempforFind Me In The Woods almost 8 years
    oh ok that makes sense
  • tempforFind Me In The Woods
    tempforFind Me In The Woods almost 8 years
    now is there a way to output a code block (ex parted -l) into the little block? I see the option "--programbox" but nothing is happening
  • tempforFind Me In The Woods
    tempforFind Me In The Woods almost 8 years
    just the dialog. Pardon my confusing english. I need parted -l to be displayed and then I can put in code somehow to capture a user entry of a letter (/dev/sd?).
  • jimmij
    jimmij almost 8 years
    @tempforFindMeInTheWoods If you want to present output of the command parted -l to the user via dialog box then probably option --menu is a better choice instead of -yesno. In such case you would have to play a bit with descriptors to store output into the variable, for example: output=$(dialog --backtitle "Package configuration" --title "Configuration sun-java-jre" --menu "$(parted -l)" 15 40 4 1 "sda1" 2 "sda2" 3 "sda3" 3>&1 1>&2 2>&3 3>&-); echo $output
  • Marius
    Marius almost 8 years
    Or, you could use the --stdout option.
  • Thawn
    Thawn almost 8 years
    @Runium: Thanks for the clarification and the link to Bash Simple Curses.
  • Ferrybig
    Ferrybig almost 8 years
    All dialog options are explained in the manual: man dialog
  • underscore_d
    underscore_d almost 8 years
    still, it was useful to mention that ncurses is the basis of this, and it answers a more general version of the question... like the one in the title here :)
  • code_dredd
    code_dredd almost 6 years
    As a note to others, remember to avoid launching the shell script with the -e option, as this will cause your scripts to automatically exit with a "failure" as soon as dialog, whiptail, etc. returns a non-zero exit code, which in their case is used to tell you what the user's selection was (e.g. yes/ok=0, no/cancel=1, ESC key=255) rather than communicating success or failure.
  • Macindows
    Macindows over 4 years
    Zenity is a good idea in your desktop where you are running a terminal in graphical environment like Ubuntu but when it is not useful for servers. I think the questioner is asking for those old Windows 95 installation interfaces.