Bash数组替换元素异常:替换元素被追加至数组末尾问题排查
数组复制与元素替换的异常问题排查
问题背景
现有两个长度相同的数组:
az0=(0 0 0 0 0 0 0 0 0 0) az=(0 45 315 90 270 120 240 150 210 180)
需求是遍历数组az,每次将az0完整复制到spaz数组,然后将spaz的第i个元素替换为az的第i个元素,最终得到如下序列:
spaz=(0 0 0 0 0 0 0 0 0 0) spaz=(0 45 0 0 0 0 0 0 0 0) spaz=(0 0 315 0 0 0 0 0 0 0) … spaz=(0 0 0 0 0 0 0 0 0 180)
现有代码
调试模式代码
for((i=0;i<${#az[@]};i++)) do spaz=${az0[@]} echo '${spaz[*]}=('`echo ${spaz[*]}`')' echo '${az[*]}=('`echo ${az[*]}`')' az=(0 45 315 90 270 120 240 150 210 180) echo "i=$i" echo '${az'[$i]'}='`echo ${az[$i]}` spaz[$i]=${az[$i]} echo '${spaz'[$i]'}'=`echo ${spaz[$i]}` echo '${spaz[*]}=('`echo ${spaz[*]}`')' echo unset spaz read -rsp $'Press any key to continue or q or CTRL-C to quit...\n' -n 1 key if [[ "$key" = "q" ]] then echo; exit; fi echo done
运行模式代码
for((i=0;i<${#az[@]};i++)) do spaz=${az0[@]} az=(0 45 315 90 270 120 240 150 210 180) spaz[$i]=${az[$i]} unset spaz done
异常现象
运行代码后出现不符合预期的结果:
- 当
i=0时,spaz变为仅含一个0的数组,而非全0数组 - 当
i≥1时,修改的元素被追加到数组末尾,而非替换对应位置的元素
异常输出片段如下:
${spaz[*]}=(0 0 0 0 0 0 0 0 0 0) ${az[*]}=(0 45 315 90 270 120 240 150 210 180) i=0 ${az[0]}=0 ${spaz[0]}=0 ${spaz[*]}=(0) ${spaz[*]}=(0 0 0 0 0 0 0 0 0 0) ${az[*]}=(0 45 315 90 270 120 240 150 210 180) i=1 ${az[1]}=45 ${spaz[1]}=45 ${spaz[*]}=(0 0 0 0 0 0 0 0 0 0 45)
问题原因
核心错误是数组复制的方式不正确:spaz=${az0[@]} 这种写法并没有复制数组,而是将az0的所有元素拼接成一个单一字符串,赋值给普通变量spaz,而非数组变量。
当后续执行spaz[$i]=${az[$i]}时,Bash会自动将普通变量spaz转换为数组,但此时原字符串会被当作数组的第0个元素:
- 当
i=0时,会直接覆盖数组第0位的字符串,导致数组仅保留一个元素 - 当
i≥1时,会在数组的第i位新增元素,原第0位的完整字符串被保留,最终输出看起来像是元素被追加到末尾
解决方案
使用正确的数组复制语法:spaz=("${az0[@]}"),双引号确保元素中的空格被保留(此处元素为数字不影响,但这是标准数组复制写法),括号和@符号确保每个元素被单独复制为spaz数组的元素。
修正后的调试模式代码
for((i=0;i<${#az[@]};i++)) do spaz=("${az0[@]}") # 修正数组复制方式 echo '${spaz[*]}=('`echo ${spaz[*]}`')' echo '${az[*]}=('`echo ${az[*]}`')' az=(0 45 315 90 270 120 240 150 210 180) echo "i=$i" echo '${az'[$i]'}='`echo ${az[$i]}` spaz[$i]=${az[$i]} echo '${spaz'[$i]'}'=`echo ${spaz[$i]}` echo '${spaz[*]}=('`echo ${spaz[*]}`')' echo unset spaz read -rsp $'Press any key to continue or q or CTRL-C to quit...\n' -n 1 key if [[ "$key" = "q" ]]; then echo; exit; fi # 修正if语句语法 echo done
修正后的运行模式代码
for((i=0;i<${#az[@]};i++)) do spaz=("${az0[@]}") # 修正数组复制方式 az=(0 45 315 90 270 120 240 150 210 180) spaz[$i]=${az[$i]} # 可添加输出语句查看结果:echo "spaz=(${spaz[*]})" unset spaz done
注:原调试代码中的if [[ "$key" = "q" ]] then存在语法错误,需添加分号修正为if [[ "$key" = "q" ]]; then,否则会触发语法报错。
内容的提问来源于stack exchange,提问作者hmj6jmh
相关产品推荐
相关产品推荐

