我正在运行 Linux 3.10.0-693.2.2.el7.x86_64,我一生都无法弄清楚为什么会发生这种情况。这似乎是一个错误,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
Run Code Online (Sandbox Code Playgroud)
我使用 set -xv 进行故障排除,但这是没有它的输出。在生产中,options[@] 将由命令设置,并且它们返回的数字将是动态的。所以我希望菜单在 $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
Run Code Online (Sandbox Code Playgroud)
t我输入的那个?我也可以避免未绑定的变量,但输入k=2or var(后者在选择中定义)。为什么以及解决什么问题(set -o nounset需要)?
在算术表达式中,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
Run Code Online (Sandbox Code Playgroud)
正如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
Run Code Online (Sandbox Code Playgroud)
这是有效的,因为var仅当用户在提示时提供有效响应时才分配一个值。否则,var设置为空。
从man bash算术评估部分:
允许外壳变量作为操作数;在计算表达式之前执行参数扩展。在表达式中,shell 变量也可以在不使用参数扩展语法的情况下按名称引用。当按名称引用而不使用参数扩展 Syn? 税。 变量的值在被引用时作为算术表达式求值,或者当使用声明 -i 赋予整数属性的变量被赋值时。空值的计算结果为 0。shell 变量无需打开其整数属性即可在表达式中使用。