我正在运行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=2
或var
(后者在select中定义)。为什么以及做什么工作
(需要set -o nounset
)?
答案 0 :(得分:4)
在算术表达式中,bash计算变量的值。因此,在(( REPLY <= ${#options[@]} ))
中,评估REPLY
的值。如果REPLY
的值为t
且t
未绑定,则会触发未绑定的变量错误。
观察:
$ 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变量不需要 其整数属性已打开以在表达式中使用。