Как интерпретировать пользовательский ввод как имя переменной?
Это довольно сложно объяснить. Рассмотрим переменные all
, first
, last
, а также some
:
a="apple mcintosh"
b="banana plantain"
c="coconut cashew"
all="$a $b $c"
first="$a"
last=$c"
some="$a $c"
Вот что у меня есть:
echo "What do you want to install?"
echo "all, first, last, or some?"
read userinput
Предполагая, что пользователь вводит all
его ввод должен рассматриваться как имя переменной: я хочу, чтобы следующая команда была pacman -S $all
(эквивалентно pacman -S apple mcintosh banana plantain coconut cashew
). Аналогично, если пользователь вводит оба first
а также last
следующая команда должна быть pacman -S $first $last
(который на самом деле должен выполнить pacman -S apple mcintosh coconut cashew
).
я использовал case/esac
переводить userinput
в переменную, но я ищу более гибкое и элегантное решение, так как этот подход не допускает более одного ввода.
case $userinput in
all) result="$all";;
first) result="$first";;
*) exit;;
esac
pacman -S $result
2 ответа
Вам нужна косвенная ссылка на переменную, которая имеет вид ${!var}
:
3.5.3 Расширение параметров оболочки
[...] Если первый символ параметра является восклицательным знаком (!), Вводится уровень косвенной косвенности. Bash использует значение переменной, сформированной из остальной части параметра, в качестве имени переменной; эта переменная затем раскрывается, и это значение используется в остальной части замещения, а не в значении самого параметра. Это известно как косвенное расширение.
Например:
$ a="apple mcintosh"
$ b="banana plantain"
$ c="coconut cashew"
$ all="$a $b $c"
$ first="$a"
$ last="$c"
$ some="$a $c"
$ read userinput
all
$ result=${!userinput}
$ echo $result
apple mcintosh banana plantain coconut cashew
Чтобы развернуть несколько элементов, используйте read -a
читать слова в массив:
$ read -a userinput
first last
$ result=$(for x in ${userinput[@]}; do echo ${!x}; done)
$ echo $result
apple mcintosh coconut cashew
Для чтения пользовательского ввода из списка вариантов, bash select
это то, что вам нужно. Кроме того, когда вы начинаете спрашивать "как динамически создать имя переменной", подумайте об ассоциативных массивах:
a="apple mcintosh"
b="banana plantain"
c="coconut cashew"
declare -A choices
choices[all]="$a $b $c"
choices[first]="$a"
choices[last]="$c"
choices[some]="$a $c"
PS3="What do you want to install? "
select choice in "${!choices[@]}"; do
if [[ -n $choice ]]; then
break
fi
done
echo "you chose: ${choices[$choice]}"
Выше не обрабатывает несколько вариантов. В этом случае, затем (все еще используя массив "choices" сверху):
options=$(IFS=,; echo "${!choices[*]}")
read -rp "What do you want to install ($options)? " -a response
values=""
for word in "${response[@]}"; do
if [[ -n ${choices[$word]} ]]; then
values+="${choices[$word]} "
fi
done
echo "you chose: $values"
Это использует read
"s -a
возможность прочитать ответ в массив. На что это похоже:
$ bash select.sh
What do you want to install (some,last,first,all)? first middle last
you chose: apple mcintosh coconut cashew