错误? bash select--键入的数据作为“未绑定的变量”返回

时间:2017-12-08 22:57:49

标签: bash select

我正在运行Linux 3.10.0-693.2.2.el7.x86_64,并且在我的生活中无法理解为什么会发生这种情况。它似乎是一个bug,而shellchecker没有发现任何问题。

#!/bin/bash
set -o nounset

### functions
options=(one two three)

select var in "${options[@]}"; do
    # make sure it is a valid choice
    if (( REPLY <= ${#options[@]} )) && [[ $REPLY  =~ ^[0-9]+$ ]]; then
        case $var in
            one)   exit;;
            two)  df -h /tmp;;
            *)      echo $var;;
        esac
        break
    else
        printf "Invalid selection.\n" >&2
    fi

我使用set -xv进行故障排除,但这是没有它的输出。在生产中,选项[@]将由命令设置,它们返回的数字将是动态的。所以我希望菜单在$ var上执行*)中的命令,但是我必须检查REPLY中的越界选择。这是输出。

$ bad_select.bash
1) one
2) two
3) three
#? 4
Invalid selection.
#? t
/home/lc5550358/bin/select_menu.wip: line 9: t: unbound variable

我输入的t?我也可以避开未绑定的变量,但是输入k=2var(后者在select中定义)。为什么以及做什么工作 (需要set -o nounset)?

1 个答案:

答案 0 :(得分:4)

在算术表达式中,bash计算变量的。因此,在(( REPLY <= ${#options[@]} ))中,评估REPLY的值。如果REPLY的值为tt未绑定,则会触发未绑定的变量错误。

观察:

$ t=2*3; REPLY=t; echo $(( REPLY + 2 ))
8
$ REPLY=t; t=a+b; a=6; b=c; c=10; echo $(( REPLY + 2 ))
18
$ unset t; REPLY=t; echo $(( REPLY + 2 ))
bash: t: unbound variable

正如jm666所解释的那样,一个解决方案是颠倒测试的顺序,这样只有在验证了REPLY是一个整数后才能在REPLY上完成算术。

或者,您可以测试var而不是REPLY

#!/bin/bash
set -o nounset

### functions
options=(one two three)

select var in "${options[@]}"; do
    # make sure it is a valid choice
    if [ "$var" ]; then
        case "$var" in
            one)   exit;;
            two)  df -h /tmp;;
            *)      echo "$var";;
        esac
        break
    else
        printf "Invalid selection.\n" >&2
    fi
done

这是有效的,因为如果用户在提示符处提供了有效的响应,则仅为var分配值。否则,var将设置为空。

文档

关于算术评估的man bash部分:

  

允许Shell变量作为操作数;参数扩展是   在评估表达式之前执行。在表达式中,   shell变量也可以通过名称引用而不使用   参数扩展语法。一个null变量或未设置的shell变量   在不使用参数的情况下按名称引用时计算结果为0   扩张法。 变量的值被评估为   算术表达式,当它被引用,或当一个变量   已经给出了使用declare -i赋值的整数属性   值。 null值的计算结果为0.一个shell变量不需要   其整数属性已打开以在表达式中使用。