-3

I want to create a menu with a script with multi choice . like :

1) 

2)

3)

4)

5)

I can choose 1 , and 3 , and 5 in the same time .

Jahid
  • 21,542
  • 10
  • 90
  • 108

1 Answers1

5

bash's select compound command doesn't directly support multiple choices, but you can still base your solution on it, taking advantage of the fact that whatever the user enters is recorded in the special $REPLY variable:

#!/usr/bin/env bash

choices=( 'one' 'two' 'three' 'four' 'five' ) # sample choices
select dummy in "${choices[@]}"; do  # present numbered choices to user
  # Parse ,-separated numbers entered into an array.
  # Variable $REPLY contains whatever the user entered.
  IFS=', ' read -ra selChoices <<<"$REPLY"
  # Loop over all numbers entered.
  for choice in "${selChoices[@]}"; do
    # Validate the number entered.
    (( choice >= 1 && choice <= ${#choices[@]} )) || { echo "Invalid choice: $choice. Try again." >&2; continue 2; }
    # If valid, echo the choice and its number.
    echo "Choice #$(( ++i )): ${choices[choice-1]} ($choice)"
  done
  # All choices are valid, exit the prompt.
  break
done

echo "Done."

As for how the select command normally works, with a single selection:

  • Run man bash and look under the heading 'Compound Commands'
  • For an annotated example, see this answer.

This answer implements custom logic as follows:

  • The designated target variable of the select command, dummy, is ignored, and the $REPLY variable is used instead, because Bash sets it to whatever the user entered (unvalidated).
  • IFS=', ' read -ra selChoices <<<"$REPLY" tokenizes the user-entered value:
    • It is fed via a here-string (<<<) to the read command
    • using instance of commas and space (,<space>) as the [Internal] Field Separator (IFS=...)
      • Note that, as a side effect, the user could use spaces only to separate their choices.
    • and the resulting tokens are stored as elements of array (-a) selChoices; -r simply turns off interpretation of \ chars. in the input
    • for choice in "${selChoices[@]}"; do loops over all tokens, i.e., the individual numbers the user chose.
    • (( choice >= 1 && choice <= ${#choices[@]} )) || { echo "Invalid choice: $choice. Try again." >&2; continue 2; } ensures that each token is valid, i.e., that it is a number between 1 and the count of choices presented.
  • echo "Choice #$(( ++i )): ${choices[choice-1]} ($choice)" outputs each choice and choice number
    • prefixed with a running index (i), which is incremented (++i) using an arithmetic expansion ($((...))) - since a variable defaults to 0 in an arithmetic context, the first index output will be 1;
    • followed by ${choices[choice-1]}, i.e., the choice string indicated by the number entered, decremented by 1, because Bash arrays are 0-based; note how choice needs no $ prefix in the array subscript, because a subscript is evaluated in an arithmetic context (as if inside $(( ... ))), as above.
    • terminated with ($choice), the chosen number in parentheses.
  • break is needed to exit the prompt; by default, select will keep prompting.
Community
  • 1
  • 1
mklement0
  • 382,024
  • 64
  • 607
  • 775