Shell数组的坑

先看现象

# 写法一:
root@localhost:~# arry=()
root@localhost:~# str=aa
root@localhost:~# if [[ "$str" =~ ${arry[*]} ]]; then echo "match"; else echo "not match"; fi
match

# 写法二:
root@localhost:~# arry=(aa bb cc)
root@localhost:~# str="a"
root@localhost:~# if [[ ${arry[*]} =~ "$str" ]]; then echo "match"; else echo "not match"; fi
match

可能会遇到的常用写法以及理解错误:
写法一arry为空数组,str为aa,在判断aa是否在arry数组的时候却返回了match
写法二arry数组有的元素(aa bb cc),str为a,在判断a是否在arry数组的时候也返回了match
很明显输出不符合我们所理解的预期。

为什么

不管是写法一还是写法二中的 =~ 实际上都是在做正则匹配,也就是在判断 =~ 前的值是否包含 =~ 后的值,在做匹配时会将 ${arry[*]} 数组元素展开为以空格分隔的字符串,如果arry为空数组则就是一个""空字符串,如果arry有值比如arry=(aa bb cc)则就是一个"aa bb cc"的字符串:

  • 写法一中 [[ "$str" =~ ${arry[*]} ]] arry数组为空,实际执行为 [[ "a" =~ "" ]],也就说检查 "a"是否包含""空字符串,结果是match;如果arry数组有值,比如 arry=(aa bb cc) ,则实际执行为 [[ "a" =~ "aa bb cc" ]] ,检查a是否包含"aa bb cc"很明显不包含,结果为not match
  • 写法二中 [[ ${arry[*]} =~ "$str" ]] arry数组有值,实际执行为 [[ "aa bb cc" =~ "a" ]] ,也就是检查 "aa bb cc"是否包含"a",结果为match

正确方式

# 方式一:使用for循环
arry=(aa bb cc)
str="a"

found=0
for item in ${arry[@]}; do
    if [[ ${item} == ${str} ]]; then
        found=1
        break
    fi
done

if (( found )); then
    echo "match"
else
    echo "not match"
fi

# 方式二:使用case
str="a"

found=0
case "${str}" in
    aa|bb|cc)
        found=1
        ;;
esac

if (( found )); then
    echo "match"
else
    echo "not match"
fi

方式二(case 语句)效率更高,适合静态列表的匹配,如果列表是固定的(如 aa|bb|cc),case 更清晰。
方式一(循环)更灵活,适合动态数组的检查,如果列表是动态的(如从数组或变量中读取),则只能用循环。

版权声明:
作者:admin
链接:https://www.chenxie.net/archives/2779.html
来源:蜀小陈
文章版权归作者所有,未经允许请勿转载。

THE END
分享
二维码
< <上一篇
下一篇>>
文章目录
关闭
目 录