Использование команды `select` для печати меню в Bash

10

Я пытаюсь реализовать простое меню с помощью selectкоманды. Сценарий (для тестирования) выглядит следующим образом:

#!/bin/bash
echo "*******************"
PS3='Select an option and press Enter: '
options=("apache" "named" "sendmail")
select opt in "${options[@]}"
do
  case $opt in
        "apache")
          date
          ;;
        "named")
          echo "test"
          ;;
        "sendmail")
          echo "test 2"
          ;;
        *) echo "invalid option";;
  esac
done
echo "*********************"

Скрипт не распознает какие-либо действительные входные данные, которые я даю, и всегда печатает сообщение «неверная опция» Что я делаю не так в этом сценарии?

Sumod
источник
4
Вы вводите 1, 2 или 3, верно?
энзотиб

Ответы:

11

Ваше меню, отображаемое выбором, будет выглядеть так:

1) apache
2) named
3) sendmail
Select an option and press Enter: 

В это время вы вводите «1» или «2» или «3»: вы не вводите слово.

Кроме того, selectбудет зацикливаться, пока не увидит breakкоманду, поэтому вы хотите это:

  case $opt in
        "apache")
          date
          break
          ;;
        "named")
          echo "test"
          break
          ;;
        "sendmail")
          echo "test 2"
          break
          ;;
        *) echo "invalid option";;
  esac

Если вы хотите разрешить пользователю вводить число или слово, вы можете написать это:

select opt in "${options[@]}"; do
  case "$opt,$REPLY" in
    apache,*|*,apache)     do_something; break ;;
    named,*|*,named)       do_something; break ;;
    sendmail,*|*,sendmail) do_something; break ;;
  esac
done

Запятая не имеет синтаксического значения, она просто для того, чтобы иметь возможность сопоставления с шаблоном либо для переменной $ REPLY (что именно ввел пользователь), либо для переменной $ opt

Гленн Джекман
источник
selectКоманда нуждается в breakне case.
Гленн Джекман
Спасибо! Я не осознавал, что это были числовые варианты. Duhh!
Сумод
Ха, я тоже программирую на C, и вам нужно breakтам в каждом разделе. Тем не менее, вы никогда не будете нуждаться в breakв случае ... ESAC блок в сценарии оболочки . Это может случиться так легко, чтобы смешать их. :-)
syntaxerror
1
@syntaxerror, вы правы, вам не нужно breakдля case. Тем не менее, вам нужно breakизбежать selectцикла.
Гленн Джекман
@glenn jackman Я бы хотел, чтобы это стало более полезным комментарием (см. далее). Так что было бы здорово, если бы вы согласились удалить свой комментарий с 12:55. Я сделаю то же самое с моим, конечно.
синтаксическая ошибка
3

Ваша $optпеременная будет установлена ​​в опциональное слово, соответствующее номеру, который вводит пользователь. Если вы хотите посмотреть, что на самом деле набрал пользователь, посмотрите $REPLY.

Кусалананда
источник
1
Учитывая, что caseсравниваются $optс «apache», «named» и «sendmail», это правильно и ничего менять не нужно.
manatwork
@manatwork, если OP не хочет, чтобы пользователь вводил слова «apache», «named» или «sendmail» вместо нажатия 1, 2 или 3.
Кусалананда
Интересно. $ REPLY удерживает 1/ 2/ 3, и $ opt удерживает apache/ named/sendmail
Peter.O
@fred, да, $REPLYэто то, что набрал пользователь, и если это было допустимое число, то оно $optбудет словом, соответствующим этому номеру.
Кусалананда