'Linux script select menu

I need to create a select menu with six options using the select loop and the case instruction BUT NOT THE ECHO COMMAND FOR THE MENU OPTION and they have to display like this:

1) opt1
2) opt2
3) opt3
4) opt4
5) opt5
6) opt6

And not like:

1) opt1 3) opt3 5) opt5
2) opt2 4) opt4 6) opt6

So far I have this code, but the problem is with the display, with 5 options it displays vertically, but with 6 it displays side by side:

#! /bin/sh
PS3="Enter your choice :"
select choice in "opt1" "opt2" "opt3" "opt4" "opt5" "Exit"; do
case $REPLY in
    1) echo "$choice";;
    2) echo "$choice";;
    3) echo "$choice";;
    4) echo "$choice";;
    5) echo "$choice";;
    6) echo "see you next time";break;;
    *) echo "Wrong choice!";;
esac
done


Solution 1:[1]

Adjusting the COLUMNS variable helps to limit the number of columns in the menu. I typically do (in a script):

COLUMNS=1
select ...

when I want one column all the time.

To be precise, COLUMNS=1 means that your TERMINAL is ONE CHARACTER wide. The select command then has no choice but to then print ONE COLUMN of menu items.

To be REALLY accurate, you could

  1. find the length of the longest item (itemLen)

THIS IS INCORRECT=> 2. find the number of items and mod by ten to get the max number of digits (numberLen) <=

  1. find the total number of items "n" and calculate int(log10(n))+1 (numberLen)
  2. COLUMNS=((itemLen + numberLen = 2))

where the '2' is for the paren and space between the menu item number and the item. But this is not necessary.

Solution 2:[2]

Try something like this:

menu()
{
    cat <<EOF
  1) opt1
  2) opt2
  3) opt3
  4) opt4
  5) opt5
  6) opt6
  q) quit
EOF

    echo -n "make your choice > <^H^H"
    read -n 1 foo
    echo

    case "$foo" in
        1|opt1) echo "opt1" ;;
        2|opt2) echo "opt2" ;;
        3|opt3) echo "opt3" ;;
        4|opt4) echo "opt4" ;;
        5|opt5) echo "opt5" ;;
        6|opt6) echo "opt6" ;;
        q|quit) echo "bye bye!" ;;
    esac
}

The ^Hs stand for the ASCII sequence 0x08 or BS (backspace).

(In vim you can type this with CTRL+v and then CTRL+h)

Solution 3:[3]

I've got the same problem. I didn't understand how exactly select uses LINES and COLUMNS (see "Shell Variables" in the bash man page), but setting COLUMNS to 1 (some small value indeed) helped me.

Solution 4:[4]

You can use the select builtin, if available:

#!/bin/bash

select o in opt{1..6}; do
    case "${o}" in
        opt[1-6])
            break
            ;;
        *)
            echo "Invalid choice '${REPLY}', please pick one of the above"
            ;;
    esac
done
echo "You picked: ${o}"

Example run:

$ ./t.sh
1) opt1
2) opt2
3) opt3
4) opt4
5) opt5
6) opt6
#? 9
Invalid choice '9', please pick one of the above
#? asdf
Invalid choice 'asdf', please pick one of the above
#? 1
You picked: opt1

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Uroc327
Solution 3
Solution 4 Adrian Frühwirth