1

How to have spaces or tabs in the menu list?

    PS3='Please enter your choice: '
    options=("Option 1" "Option 2" "Quit")
    select opt in "${options[@]}"
    do
      case $opt in
         "Option 1")
            echo "Your choise is 1"
            ;;
         "Option 2")
            echo "Your choise is 2"
            ;;
         "Quit")
            break
            ;;
         *) echo "Invalid option;;
      esac
    done

And I got this:

[user@Server:/home/user] ./test.sh
1) Option 1
2) Option 2
3) Option 3
4) Quit
Please enter your choice:

But I'd like something like this:

[user@Server:/home/user] ./test.sh
   1) Option 1
   2) Option 2
   3) Option 3
   4) Quit
Please enter your choice:

Ideas?

1
  • 2
    This has nothing to do with the case statement. It's the select that displays the menu. As an aside note: If you use case $REPLY in, you can test on the numbers instead. That way you don't have to repeat all those strings. Commented Dec 12, 2018 at 6:36

2 Answers 2

2

It's not too hard to (roughly) reimplement select manually and fine-tune the display, at least as long as you don't have so many options to need a multi-column listing.

#!/bin/bash

# print the prompt from $1, and a menu of the other arguments
choose() {
    local prompt=$1
    shift
    local i=0
    for opt in "$@"; do
        # we have to do the numbering manually...
        printf "  %2d) %s\n" "$((i += 1))" "$opt"
    done
    read -p "$prompt: "
}

options=("Foo" "Bar" "Quit")
while choose 'Please enter your choice'  "${options[@]}"; do
    case $REPLY in
    1) echo "you chose 'foo'" ;;
    2) echo "you chose 'bar'";;
    3) echo 'you chose to quit'; break;;
    *) echo 'invalid choice';;
    esac
done

Of course, this could be extended to take the array keys (indices) into account, and to present them as the choices in the menu, instead of a running counter.

1

The select statement in bash, which is what displays the menu, does not allow specifying an indent for the menu.


Just a comment on the code: It's usually easier to let the case statement act on $REPLY rather than the variable with the selected string. It saves you from having to type in the strings twice.

E.g.

select opt in "${options[@]}"
do
  case $REPLY in
     1)
        echo "Your choice is 1"
        ;;
     2)
        echo "Your choice is 2"
        ;;
     3)
        break
        ;;
     *) echo 'Invalid option' >&2
  esac
done

or, for this specific example,

select opt in "${options[@]}"
do
  case $REPLY in
     [1-2])
        printf 'Your choice is %s\n' "$REPLY"
        ;;
     3)
        break
        ;;
     *) echo 'Invalid option' >&2
  esac
done

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.