如何创建并直接复用BASH布尔值数组进行逻辑运算?
Bash井字棋脚本:布尔值数组构建与使用问题
我在优化一款Bash井字棋脚本时,遇到了无法构建布尔值数组(存储test命令执行结果)并在后续复杂逻辑中复用的问题。
尝试的数组赋值代码
bmap[0]="dummy" bmap[1]=$( test ${board[1]} == ${symbol} ) bmap[2]=$( test ${board[2]} == ${symbol} ) bmap[3]=$( test ${board[3]} == ${symbol} ) bmap[4]=$( test ${board[4]} == ${symbol} ) bmap[5]=$( test ${board[5]} == ${symbol} ) bmap[6]=$( test ${board[6]} == ${symbol} ) bmap[7]=$( test ${board[7]} == ${symbol} ) bmap[8]=$( test ${board[8]} == ${symbol} ) bmap[9]=$( test ${board[9]} == ${symbol} )
数组使用逻辑
if \ [[ ${bmap[1]} && ${bmap[2]} && ${bmap[3]} ]] || [[ ${bmap[4]} && ${bmap[5]} && ${bmap[6]} ]] || [[ ${bmap[7]} && ${bmap[8]} && ${bmap[9]} ]] || [[ ${bmap[1]} && ${bmap[4]} && ${bmap[7]} ]] || [[ ${bmap[2]} && ${bmap[5]} && ${bmap[8]} ]] || [[ ${bmap[3]} && ${bmap[6]} && ${bmap[9]} ]] || [[ ${bmap[1]} && ${bmap[5]} && ${bmap[9]} ]] || [[ ${bmap[3]} && ${bmap[5]} && ${bmap[7]} ]] then echo "true" else echo "false" fi
运行错误信息
./test_175.sh: line 29: test: ==: unary operator expected ./test_175.sh: line 30: test: ==: unary operator expected ./test_175.sh: line 31: test: ==: unary operator expected ./test_175.sh: line 32: test: ==: unary operator expected ./test_175.sh: line 33: test: ==: unary operator expected ./test_175.sh: line 34: test: ==: unary operator expected ./test_175.sh: line 35: test: ==: unary operator expected ./test_175.sh: line 36: test: ==: unary operator expected
核心问题
是否可以直接将bmap数组的值作为布尔运算结果复用,无需再次对这些值进行测试?
问题根源与解决方案
首先,你遇到的test: ==: unary operator expected错误,是因为${board[N]}或${symbol}可能为空值,导致test命令只接收到一个操作数和==,不符合二元比较的语法要求。解决这个问题的第一步是给变量加上引号:
bmap[1]=$( test "${board[1]}" == "${symbol}" )
但更关键的是:Bash里没有真正的布尔值类型,你用$(test ...)捕获的是命令的输出(test命令成功时没有任何输出,失败时也没有),所以bmap数组里的元素要么是空字符串,要么还是空字符串——这根本没法用来做布尔判断。
要实现你的需求,正确的做法是存储命令的退出状态码(0表示成功/真,非0表示失败/假),或者直接用0/1来标记布尔状态:
方案1:存储退出状态码
# 赋值时直接保存命令的退出状态 for i in {1..9}; do test "${board[$i]}" == "${symbol}" bmap[$i]=$? done # 使用时检查退出状态是否为0(真) if \ [[ ${bmap[1]} -eq 0 && ${bmap[2]} -eq 0 && ${bmap[3]} -eq 0 ]] || [[ ${bmap[4]} -eq 0 && ${bmap[5]} -eq 0 && ${bmap[6]} -eq 0 ]] || [[ ${bmap[7]} -eq 0 && ${bmap[8]} -eq 0 && ${bmap[9]} -eq 0 ]] || [[ ${bmap[1]} -eq 0 && ${bmap[4]} -eq 0 && ${bmap[7]} -eq 0 ]] || [[ ${bmap[2]} -eq 0 && ${bmap[5]} -eq 0 && ${bmap[8]} -eq 0 ]] || [[ ${bmap[3]} -eq 0 && ${bmap[6]} -eq 0 && ${bmap[9]} -eq 0 ]] || [[ ${bmap[1]} -eq 0 && ${bmap[5]} -eq 0 && ${bmap[9]} -eq 0 ]] || [[ ${bmap[3]} -eq 0 && ${bmap[5]} -eq 0 && ${bmap[7]} -eq 0 ]] then echo "true" else echo "false" fi
方案2:直接存储0/1标记
# 赋值时用条件判断生成0/1 for i in {1..9}; do if [[ "${board[$i]}" == "${symbol}" ]]; then bmap[$i]=1 else bmap[$i]=0 fi done # 使用时检查是否为1(真) if \ [[ ${bmap[1]} -eq 1 && ${bmap[2]} -eq 1 && ${bmap[3]} -eq 1 ]] || [[ ${bmap[4]} -eq 1 && ${bmap[5]} -eq 1 && ${bmap[6]} -eq 1 ]] || [[ ${bmap[7]} -eq 1 && ${bmap[8]} -eq 1 && ${bmap[9]} -eq 1 ]] || [[ ${bmap[1]} -eq 1 && ${bmap[4]} -eq 1 && ${bmap[7]} -eq 1 ]] || [[ ${bmap[2]} -eq 1 && ${bmap[5]} -eq 1 && ${bmap[8]} -eq 1 ]] || [[ ${bmap[3]} -eq 1 && ${bmap[6]} -eq 1 && ${bmap[9]} -eq 1 ]] || [[ ${bmap[1]} -eq 1 && ${bmap[5]} -eq 1 && ${bmap[9]} -eq 1 ]] || [[ ${bmap[3]} -eq 1 && ${bmap[5]} -eq 1 && ${bmap[7]} -eq 1 ]] then echo "true" else echo "false" fi
更简洁的写法:直接在判断中复用逻辑
其实你也可以不用数组,直接把判断逻辑封装成函数,减少重复代码:
check_cell() { [[ "${board[$1]}" == "${symbol}" ]] } if \ (check_cell 1 && check_cell 2 && check_cell 3) || (check_cell 4 && check_cell 5 && check_cell 6) || (check_cell 7 && check_cell 8 && check_cell 9) || (check_cell 1 && check_cell 4 && check_cell 7) || (check_cell 2 && check_cell 5 && check_cell 8) || (check_cell 3 && check_cell 6 && check_cell 9) || (check_cell 1 && check_cell 5 && check_cell 9) || (check_cell 3 && check_cell 5 && check_cell 7) then echo "true" else echo "false" fi
这样既避免了数组的问题,代码也更易读维护。
内容的提问来源于stack exchange,提问作者Eric Marceau
相关产品推荐
相关产品推荐

