1

I'm looking for a tool for displaying inline menus in the shell which can be navigated with arrow-keys and enter. By "inline", I mean that the menu is displayed within the normal flow of stdout text, not in a pop-up dialog on top of everything.

I only found that post trying to address that, but it only mentions either custom scripting or non-inline/pop-up solutions (like dialog or zenity).

What I am looking for is a robust package that I could simply install within a Docker image using apt-get or npm install -g and invoke from my scripts with a list of choices and get back the user's selected item.

In nodeJS, I am using Inquirer which offers not only that kind of menus, but also all sorts of inputs.

Here's an example screenshot of such an inline menu.

The tool does not have to be written in shell script. It can be a binary/script written in any language, as long as it's rather easy to install using apt-get/curl. Even a nodeJS tool would be fine, as long as it's invokable from a shell script to pass it the choices.

1

I used to use iselect for this, many years ago.

A very basic example:

$ sel="$(iselect -a 'foo' 'bar')"
$ echo $sel
foo

From man iselect:

iSelect is an interactive line selection tool for ASCII files, operating via a full-screen Curses-based terminal session. It can be used either as an user interface frontend controlled by a Bourne-Shell, Perl or other type of script backend as its wrapper or in batch as a pipe filter (usually between grep and the final executing command). In other words: iSelect was designed to be used for any types of interactice line-based selections.

Input Data

Input is read either from the command line (line1 line2 ...) where each argument corresponds to one buffer line or from stdin (when no arguments are given) where the buffer lines are determined according to the newline characters.

You can additionally let substrings displayed in Bold mode for non-selectable lines (because the selectable lines are always displayed bold) by using the construct "<b>"..."</b>" as in HTML.

  • BTW, before compiling and installing iselect from source, check to see if it's already packaged for your distribution (it is for debian). Install the package if one is available. – cas Sep 6 at 1:17
  • Tried that and liked it; it works much like bash select meets less, and the options are much more convenient compared to dialog or whiptail. However it doesn't show the text "within the normal flow of text" as required by the OP, as any other curses based dialog I know. – Murphy Sep 6 at 7:21
  • yeah, it's pretty simple and good at what it does. I don't know what, exactly, the OP means by "within the normal flow of text" except, by example, not like dialog or zenity. iselect is quite unlike both dialog and zenity. and whiptail. And if he wants arrow-keys for cursor movement, that means ncurses (or equivalent). – cas Sep 6 at 7:36
  • My guess on the intention is that he wants the output of the selection dialog to be displayed within the other output (echos etc.) of the script, and to my knowledge select is the only option here. – Murphy Sep 6 at 7:39
  • 1
    The exploit seems to be of the order of "if you have a shell and run iselect with bad args, you can get it to give you a shell". no privilege escalation...would be bad if combined with sudo but if sudo is configured to allow an untrusted user to run something obscure like iselect, it's probably configured to allow any command to be run with sudo, including sudo bash. it's not good, but probably not worth worrying about. – cas Sep 7 at 0:22
1

A very basic approach to this would be to use bash's select statement; no need to install anything (else). Here's an example I've just got at hand:

#!/bin/bash

[...]

sourceBranch=
targetBranch=
# Force one option per line
columnsBackup=${COLUMNS}
COLUMNS=40

echo "Select source and target branch:"
select branches in \
    "testing -> release-candidate" \
    "release-candidate -> stable-release" \
    "stable-release -> stable"
do
    if [ -z "${branches}" ]; then
        echo "Invalid selection"
        continue
    fi

    sourceBranch="${branches%% -> *}"
    targetBranch="${branches##* -> }"
    break
done

COLUMNS=${columnsBackup}
echo "Releasing from ${sourceBranch} to ${targetBranch}"

[...]

Output:

Select source and target branch:
1) testing -> release-candidate
2) release-candidate -> stable-release
3) stable-release -> stable
#? 1   
Releasing from testing to release-candidate

You'll probably do some case ... esac handling in the do ... done block instead.

  • Indeed, that would minimally get the job done, but as I pointed out in my question, I'm looking for something more modern, using up/down arrow-keys to move a highlight and choosing the highlighted item with ENTER. Have a look at this animated gif for a good example of such a prompt. – Mathieu Frenette Sep 5 at 19:16
  • +1 for Murphy's suggestion. @MathieuFrenette: short of rolling your own, I don't quite see what more you could ask for. OP is fine, although not quite in style with what is usually asked here, but really there would be only minimal work involved in adapting Murphy's solution to what you want. In fact you could even think of sprucing the given script up by add dynamic key bindings to suit your needs if you reallly, .... really want arrow movements and arrow selection instead of typing in a number. There is a place called "diminishing returns" though, which you might want to avoid. – Cbhihe Sep 5 at 21:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.