【问题标题】:How to interpret user input as a variable name?如何将用户输入解释为变量名?
【发布时间】:2013-08-02 16:29:15
【问题描述】:

这个有点难以解释。考虑变量allfirstlastsome

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)。同样,如果用户同时键入firstlast,则下一个命令必须是pacman -S $first $last(实际上应该执行pacman -S apple mcintosh coconut cashew)。

我使用case/esacuserinput 转换为变量,但我正在寻找一种更灵活、更优雅的解决方案,因为这种方法不允许多个输入。

case $userinput in                                             
  all)   result="$all";;
  first) result="$first";;
  *)     exit;;
esac

pacman -S $result

【问题讨论】:

    标签: bash variables case indirection pacman-package-manager


    【解决方案1】:

    您需要的是indirect variable reference,其格式为${!var}

    3.5.3 Shell参数扩展

    [...] 如果 parameter 的第一个字符是感叹号 (!),则引入了变量间接级别。 Bash 使用由 parameter 的其余部分形成的变量的值作为变量的名称;然后扩展此变量,并将该值用于替换的其余部分,而不是 parameter 本身的值。这称为间接扩展。

    例如:

    $ 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
    

    【讨论】:

    • 不错的答案!我刚刚写了一个使用eval 的方法,但你的方法更加优雅,所以我放弃了我的答案。
    • 它确实很优雅,但它仍然无法处理多个输入。不过,很高兴终于知道它是如何被调用的。
    【解决方案2】:

    要从选项列表中读取用户输入,您需要 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]}"
    

    以上不处理多项选择。在这种情况下,那么(仍然使用上面的“选择”数组):

    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-a 选项将响应读入数组。它的样子:

    $ bash select.sh 
    What do you want to install (some,last,first,all)? first middle last
    you chose: apple mcintosh coconut cashew 
    

    【讨论】:

      猜你喜欢
      • 2019-12-02
      • 2016-10-04
      • 2015-07-01
      • 2016-11-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-26
      相关资源
      最近更新 更多