Bash中判断数组元素是否存在于另一数组时含特殊字符元素报错的问题求助
嗨,这个问题我太熟了!先给你拆解清楚问题根源,再给你靠谱的解决方案。
首先,你遇到的syntax error: invalid arithmetic operator错误,本质是你原来的代码逻辑完全错了,还踩了Bash数组的语法坑:
你写的${array2[${array1[$i]}]}这个写法,Bash会把方括号里的${array1[$i]}当成算术表达式来解析——也就是说,它会把c.sh当成一个要计算的数值,但c.sh里的小数点根本不是合法的算术运算符,所以直接报错了。
更要命的是,你第一个例子能“正常输出”其实纯粹是巧合!比如第一个例子里array1的元素是c,${array2[c]}其实是在拿变量c的值当索引,而你没定义过变量c,它默认是空值,在算术上下文里空值会被当成0,所以${array2[c]}等价于${array2[0]},刚好array2[0]是c,和array1的元素c相等,才碰巧输出了正确结果,这逻辑完全不是“检查元素是否在另一个数组里”。
给你两个靠谱的解决方案:
方案1:直接遍历对比(简单直观,适合小数组)
这个方法就是对array1的每个元素,挨个和array2的元素对比,完全不碰索引,不管元素里有啥特殊字符都能正常工作:
array1=(a b c.sh) array2=(c.sh d e) for elem in "${array1[@]}"; do for match in "${array2[@]}"; do if [[ "$elem" == "$match" ]]; then echo "$elem" break # 找到匹配就跳出内层循环,不用继续找了 fi done done
方案2:用关联数组优化(效率更高,适合大数组)
如果你的数组元素很多,循环遍历效率低,可以把array2转成关联数组(相当于哈希表),这样查询元素是否存在是O(1)的速度:
array1=(a b c.sh) array2=(c.sh d e) # 把array2的元素转成关联数组的键,值随便设个标记就行 declare -A array2_map for elem in "${array2[@]}"; do array2_map["$elem"]=1 done # 遍历array1,检查元素是否在关联数组的键中 for elem in "${array1[@]}"; do if [[ -n "${array2_map[$elem]}" ]]; then echo "$elem" fi done
至于你尝试的用::-2去掉扩展名的操作,其实完全没必要——因为问题根本不是扩展名,而是你原来的逻辑从根上就错了,就算去掉扩展名,也解决不了索引解析的问题,反而会引入新的bug(比如元素长度不足2的时候会截断出问题)。
备注:内容来源于stack exchange,提问作者Abbatrombone

