BASH: лучший способ установить переменную из массива

#arrays #bash #validation

#массивы #bash #проверка

Вопрос:

Bash 4 в Linux ~
У меня есть массив возможных значений. Я должен ограничить пользовательский ввод этими значениями.

 Arr=(hello kitty goodbye quick fox)
  

Пользователь предоставляет значение в качестве аргумента скрипту:

 bash myscript.sh -b var
  

В настоящее время я пытаюсь выполнить следующее:

 function func_exists () {
_var="$1"
for i in ${Arr[@]}
do
    if [ "$i" == "$_var" ]
    then
        echo hooray for "$_var"
        return 1
    fi
done
    return 0
}

func_exists $var
if [ $? -ne 1 ];then
    echo "Not a permitted value."
    func_help
    exit $E_OPTERROR
fi
  

Кажется, работает нормально, есть ли лучшие методы для проверки пользовательского ввода на соответствие массиву разрешенных значений?

ОБНОВЛЕНИЕ: Мне нравится ответ Джона К…может кто-нибудь разъяснить использование $ @? Я понимаю, что это представляет все позиционные параметры — поэтому мы удаляем первый параметр из стека, а $ @ теперь представляет все остальные параметры, являющиеся переданным массивом … это правильно? Я ненавижу слепо использовать код без понимания…даже если это сработает!

Ответ №1:

Ваше решение — это то, что я бы сделал. Возможно, используя еще несколько оболочек, таких как возврат 0 для успеха и не-0 для сбоя, как это обычно делают команды UNIX.

 # Tests if $1 is in the array ($2 $3 $4 ...).
is_in() {
    value=$1
    shift

    for i in "$@"; do
        [[ $i == $value ]] amp;amp; return 0
    done

    return 1
}

if ! is_in "$var" "${Arr[@]}"; then
    echo "Not a permitted value." >amp;2
    func_help
    exit $E_OPTERROR
fi
  

Тщательное использование двойных кавычек гарантирует, что это сработает, даже если отдельные записи массива содержат пробелы, что разрешено. Это массив из двух элементов: list=('hello world' 'foo bar') .

Комментарии:

1. Приятные улучшения! Спасибо! За исключением дальнейшего совершенствования, это получит мой голос.

2. Мое понимание значения $ @ в вашей функции: переместите первый аргумент из стека — $ @ теперь представляет остаток. Правильно ли это?

Ответ №2:

Другое решение. is_in — это просто переменная:

 Arr=(hello kitty goodbye quick fox)

var='quick'

string=" ${Arr[*]} "                            # array to string, framed with blanks
is_in=1                                         # false
# try to delete the variable inside the string; true if length differ 
[ "$string" != "${string/ ${var} /}" ] amp;amp; is_in=0

echo -e "$is_in"
  

Комментарии:

1. Отличное решение. Спасибо! Я оставлю это на потом.

Ответ №3:

 function func_exists () {
  case "$1"
  in
    hello)
    kitty)
    goodbye) 
    quick)
    fox)
      return 1;;
    *)
      return 0;;
  esac
}
  

Комментарии:

1. Проголосовавшему против: извините, вы видели мой ответ в тот момент, когда я случайно отправил его из-за нажатия неправильной клавиши. 🙂

2. Это хорошее решение, но я не уверен, насколько оно было бы читабельным, если бы допустимый входной массив содержал 50-100 элементов.

3. Также можно было бы компактно записать ее в одном случае как hello|kitty|goodbye|quick|fox) .

4. Я думаю, что для универсальности и удобочитаемости подойдет массив, извлеченный из файла. Не уверен, что это самый эффективный способ проверить входные данные в таком массиве. Решение должно быть способно эффективно и доступно для чтения обрабатывать массивы с более чем 50 элементами.

5. Еще одно преимущество отдельно определенного массива заключается в том, что вы можете передать массив с переменной для тестирования и иметь функцию повторного использования.