Установите переменные с помощью пользовательского ввода и убедитесь, что все переменные были установлены, прежде чем продолжить сценарий

Решение было очень простым. Мне просто нужно было добавить порт 8443 в список доступных портов Yast Firewall. На скриншоте это вкладка «Порты». После этого веб-приложение стало доступно из хост-ОС.

1
27.11.2020, 10:23
1 ответ

Хорошо, сначала несколько очевидных проблем. ${script_variables[@]}заменяется на весь массив $script_variables, разделенный пробелом. Таким образом, ваш test -z "${script_variables[@]}"всегда будет ложным, поскольку вы определяете массив в начале скрипта, поэтому "${script_variables[@]}"никогда не будет пустым. Когда вы хотите сослаться на элемент массива, вам нужно использовать определенный числовой индекс:"${script_variables[0]}"для 1-го элемента, "${script_variables[1]}"для второго и т. д.

Во-вторых, когда вы readвводите значение в переменную, вам необходимо сохранить его в переменной. Однако вы даете readрасширенный массив, который представляет собой просто значения, хранящиеся в массиве:

$ echo "${script_variables[@]}"
admin_user_name admin_user_password

Что еще более важно, вы, кажется, хотите сохранить значение, которое дает пользователь, в переменной, которую затем можно вызвать по имени. Это, когда вы устанавливаете var="foo", а затем имеете variableName="var"и пытаетесь получить значение переменной с именем var(, поэтому «foo» в этом случае )называется «косвенным расширением». ". Синтаксис для этого ${!variableName}. Например:

$ var="foo"
$ variableName="var"
$ echo "${!variableName}"
foo

Итак, вы можете использовать либо это, либо два массива :один для хранения имен переменных, а другой для хранения их значений. Или, что еще лучше в современных версиях bash, используйте единыйассоциативный массив , чьи ключи будут именами переменных. Вот рабочая версия вашего скрипта, использующая непрямое расширение:

#/bin/bash

script_variables=(
    admin_user_name
    admin_user_password
)

## This will be used to exit the loop
allSet="";

while [[ -z $allSet ]]; do
  for varName in "${script_variables[@]}"; do 
    ## No need to loop the whole thing, just loop
    ## until this particular variable has been set
    while [[ -z ${!varName} ]]; do
      read -p "Enter value for $varName: " $varName
    done
  done

  ## We will only exit the loop once all vars have been set.
  ## Now print and check them.
  printf '\n=========\nYou have entered:\n'
  for varName in "${script_variables[@]}"; do 
    printf '%s=%s\n' "$varName" "${!varName}"
  done

  while true; do
    read -p "Are the variables correct? " yn
    case $yn in
      [Yy]* )
        echo "All variables have been set. The script will now continue.";
        ## Setting this to 1 exits the top "while [[ -z $allSet ]]; do" loop
        allSet=1
        break;;
      [Nn]* )
        ## Clear the stored values to start again
        for varName in "${script_variables[@]}"; do
          unset $varName
        done
        
        break;;
      * )
        echo "Please answer yes or no.";;
    esac
  done
done

А вот вариант с использованием ассоциативного массива:

#/bin/bash

declare -A script_variables=(
    [admin_user_name]=""
    [admin_user_password]=""
)

## This will be used to exit the loop
allSet="";

while [[ -z $allSet ]]; do
  ## '${!array[@]}' returns all keys of an associative array
  for varName in "${!script_variables[@]}"; do
    read -p "Enter value for $varName: " script_variables[$varName]
  done

  ## We will only exit the loop once all vars have been set.
  ## Now print and check them.
  printf '\n=========\nYou have entered:\n'
  for varName in "${!script_variables[@]}"; do 
    printf '%s=%s\n' "$varName" "${script_variables[$varName]}"
  done

  while true; do
    read -p "Are the variables correct? " yn
    case $yn in
      [Yy]* )
        echo "All variables have been set. The script will now continue.";
        ## Setting this to 1 exits the top "while [[ -z $allSet ]]; do" loop
        allSet=1
        break;;
      [Nn]* )
        ## Clear the stored values to start again
        for varName in "${!script_variables[@]}"; do
          script_variables[$varName]=""
        done
        
        break;;
      * )
        echo "Please answer yes or no.";;
    esac
  done
done

Лично я бы использовал несколько иной подход. Вместо того, чтобы настраивать все, а затем позволять пользователю проверять в конце, я бы проверял все по мере ввода. Таким образом, вы получаете ошибки в начале и вам не нужно -переустанавливать все переменные, а только ту, в которой вы ошиблись. Примерно так:

#/bin/bash

declare -A script_variables=(
    [admin_user_name]=""
    [admin_user_password]=""
)

allSet=0;

while [[ $allSet -lt ${#script_variables[@]} ]]; do
  for varName in "${!script_variables[@]}"; do
        ok=""
        while [[ $ok != [Yy]* ]]; do
          read -p "Enter value for $varName: " script_variables[$varName]
          read -p "You entered '${script_variables[$varName]}'. Is this correct? " ok
        done
        ## If we're satisfied, increment the value of allSet
        ((allSet++))
  done
done

## You can add a second test here, but just exit the script if it's wrong.
## There's no point in complicating your code if you're just going back to
## the beginning anyway: just exit and rerun it.
printf '\n=========\nYou have entered:\n'
for varName in "${!script_variables[@]}"; do 
  printf '%s=%s\n' "$varName" "${script_variables[$varName]}"
done

read -p "Is everything OK? (y/n; n will exit the script)": yn
if [[ $yn != [Yy]* ]]; then
   exit
fi

echo "Everything correctly set, continuing!"
1
18.03.2021, 23:02

Теги

Похожие вопросы