You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Bash二维数组赋值异常问题求助

Bash二维数组赋值异常问题求助

最近我遇到一个奇怪的脚本行为,至今搞不懂数组为什么会这样表现。

先贴一段脚本代码:

for nCDATAReg in $(seq 1 4)
do
    sTestBuffer1=$(grep -Pzoi '\/\/<\!\[CDATA\[[\s\S]*?\/\/\]\]>' $SOMEFILE | sed  -rz 's/\/\/<\!\[CDATA\[\n(.*)\/\/\]\]>/\1/g' | tr -d '\0' | sed -rz 's/InsertData\(([[:digit:]]+), [[:digit:]]+, \{(.*?)\}\)\;/\1/gm' | sed "${nCDATAReg}q;d")
    printf "\t\t\t\t\tDEBUG: Buffer is: $sTestBuffer1\t"

    aCDATA[0,$nCDATAReg]=$sTestBuffer1

    sTestBuffer2=$(grep -Pzoi '\/\/<\!\[CDATA\[[\s\S]*?\/\/\]\]>' $SOMEFILE | sed  -rz 's/\/\/<\!\[CDATA\[\n(.*)\/\/\]\]>/\1/g' | tr -d '\0' | sed -rz 's/InsertData\(([[:digit:]]+), [[:digit:]]+, \{(.*?)\}\)\;/\2/gm' | sed "${nCDATAReg}q;d")

    aCDATA[1,$nCDATAReg]=$sTestBuffer2

    printf "and second Buffer is: $sTestBuffer2\t\n"  # 注:原脚本里这里写的是$sTestBufferS,应该是笔误
    printf "But array now contains: (${aCDATA[0,$nCDATAReg]}) and (${aCDATA[1,$nCDATAReg]})\n"
done

对应的文件$SOMEFILE内容如下:

MORE TEXT ABOVE

</script>

<script>//<![CDATA[

InsertData(1, 1, {VALUE1});

InsertData(3, 1, {value2});

InsertData(6, 1, {vALUE3});

InsertData(91, 1, {Value4});

//]]></script>    <div class="news-post news-post-style-full"

MORE TEXT BELOW

理论上(控制台单独测试正则也没问题),这段代码应该把每个InsertData里的第一个数字和大括号里的内容分别提取出来,先存到变量里再赋值给数组的对应位置。变量里的值是对的,比如第一次循环sTestBuffer1是1,sTestBuffer2是VALUE1,但数组里两个位置却都变成了VALUE1。

实际输出如下:

DEBUG: Buffer is: 1     and second Buffer is: VALUE1            But array now contains: (VALUE1) and (VALUE1)
DEBUG: Buffer is: 3     and second Buffer is: value2            But array now contains: (value2) and (value2)
DEBUG: Buffer is: 6     and second Buffer is: vALUE3            But array now contains: (vALUE3) and (vALUE3)
DEBUG: Buffer is: 91    and second Buffer is: Value4            But array now contains: (Value4) and (Value4)

我到底哪里弄错了?(除了明显的Bash基础薄弱之外😂)


问题根源分析

你遇到的核心问题是:Bash没有原生的二维数组,而且你用的下标写法被Bash当成了算术表达式解析!

在Bash中,普通的索引数组(默认的数组类型)只能用整数作为下标。当你写aCDATA[0,$nCDATAReg]时,Bash会把方括号里的内容当作算术表达式来计算。而算术表达式里的逗号是顺序求值运算符——它会执行所有子表达式,最后返回最后一个子表达式的值。

举个例子:

  • 当nCDATAReg=1时,0,$nCDATAReg会被解析成0,1,算术运算结果是1
  • 同样,1,$nCDATAReg解析成1,1,结果也是1

也就是说,你每次循环都是在给数组的同一个索引($nCDATAReg的值)赋值两次:第一次赋sTestBuffer1,第二次赋sTestBuffer2,所以最后数组里这个索引的值会被第二次的覆盖。而你访问的时候,两个下标表达式计算后都是同一个索引,自然取到的都是第二次赋值的内容。

解决方案

有两种常见的解决方式:

方式一:使用关联数组

关联数组支持用字符串作为下标,不会把下标当作算术表达式解析。只需要在使用数组前先声明它为关联数组:

# 在脚本开头、数组使用前添加这行
declare -A aCDATA

之后再用aCDATA["0,$nCDATAReg"]=$sTestBuffer1和aCDATA["1,$nCDATAReg"]=$sTestBuffer2赋值(引号可以省略,但加上更清晰),访问的时候用${aCDATA["0,$nCDATAReg"]}就能正确获取对应的值了。

方式二:用一维数组模拟二维数组

如果你不想用关联数组,可以把二维结构映射到一维数组里,比如按行或按列排列:

# 比如用索引 (nCDATAReg-1)*2 存第一个值,(nCDATAReg-1)*2+1 存第二个值
aCDATA[$(( (nCDATAReg - 1) * 2 ))]=$sTestBuffer1
aCDATA[$(( (nCDATAReg - 1) * 2 + 1 ))]=$sTestBuffer2

# 访问时对应取:
printf "But array now contains: (${aCDATA[$(( (nCDATAReg - 1) * 2 ))]}) and (${aCDATA[$(( (nCDATAReg - 1) * 2 + 1 ))]})\n"

或者更直观一点,分开用两个一维数组,比如aCDATA_ID存数字部分,aCDATA_VALUE存大括号里的内容,这样逻辑更清晰,也不容易出错。


备注:内容来源于stack exchange,提问作者Talcott Parsons

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.23 16:07:29