本文使用 Bash 数组;POSIX sh 不支持这套语法。关联数组需要 Bash 4.0 或更高版本,macOS 自带的 Bash 3.2 不支持,可以先用 bash --version 确认。

数组的类型

普通数组

  • 索引:通常是从0开始的整数,表示数组中的位置
    • 例如,第一个元素的索引是0,第二个元素的索引是1,依此类推
  • 元素:存储在数组中的实际值,每个索引对应一个元素值
    • 例如,my_array[0] 表示数组中的第一个元素。
  • 普通数组可以直接赋值,也可以先声明:declare -a 数组名
1
2
3
my_array=("apple" "banana" "cherry")
# 索引: 0 1 2
# 元素: "apple" "banana" "cherry"

关联数组

  • 索引:在关联数组中,索引作为字符串键处理,可以是单词,也可以是数字形式的字符串;键不能为空

    • 每个索引表示一个键,它与一个特定的元素值相关联。
    • 与普通数组最大的区别,其由特定格式的键值对组成
  • 元素:元素是与索引关联的值

    • 关联数组中的每个索引都映射到一个元素值。
  • 使用前必须声明(declare -A 数组名)

1
2
3
4
5
6
declare -A fruit_colors
fruit_colors["apple"]="red"
fruit_colors["banana"]="yellow"
fruit_colors["cherry"]="red"
# 索引: "apple" "banana" "cherry"
# 元素: "red" "yellow" "red"

数组的定义

直接定义

格式为 array_name=(value1 value2 ... valueN)

1
array=(a b c)

索引定义

格式为 array_name=( [1]=value1 [2]=value2 ... [N]=valueN )

1
array=([1]=a [2]=b [3]=c)

数组的取值

要访问数组中的值,可以使用${数组名[索引]}

读取索引

这用于获取数组的索引(或键),而不是数组元素本身

echo "${!array[*]}" :视为整体

printf '%s\n' "${!array[@]}" :视为个体

读取数值

返回的是数组中的所有元素,不包括索引

echo "${array[*]}" :视为整体

printf '%s\n' "${array[@]}" :视为个体

💡提示:"${array[*]}" 将元素合为一个字符串;"${array[@]}" 保留每个元素的边界。这里用 printf 每项输出一行,含空格的元素也不会被拆开。关联数组遍历顺序不应当作插入顺序来依赖。

特定元素

echo "${array[0]}" :访问索引为 0 的元素(前面的 array=([1]=a [2]=b [3]=c) 没有索引 0)

printf '%s\n' "${array[@]:1}" :表示从索引 1 开始,包括索引 1 及之后的所有元素

printf '%s\n' "${array[@]:1:2}" :从索引偏移 1 开始取最多两个已有元素;索引从 0 连续排列时,就是第二、第三个元素

其他用法

echo ${#array[@]} : 获取数组中的元素个数(数组的长度)

echo ${#array[n]} :获取数组中索引为 n 的元素的字符个数

数组的遍历

通过索引

  • 如:循环以索引 i 来迭代数组 array
  • 适合需要根据元素的索引处理数组元素的情况
1
2
3
4
5
6
#!/bin/bash
names=(Tom Jeny David)
for i in "${!names[@]}"
do
echo "${names[$i]}"
done

删除元素后索引不会自动重排,所以遍历实际存在的索引更稳妥,不能总是假设索引是 0 到“元素个数减一”。

通过元素

  • 如:循环迭代数组 array 中的每个元素,并将每个元素赋值给变量 i
  • 适合需要依次访问数组元素的情况
1
2
3
4
5
6
7
8
#!/bin/bash
names=(Tom Jeny David)
index=0
for i in "${names[@]}"
do
echo "第${index}个元素的值为:${i}"
index=$((index + 1))
done

数组删切替

删除

使用 unset 'array[index]' 命令,可以删除数组中的特定元素

  • array 是数组名
  • index 是索引

切片

使用 ${array[@]:start:length} 命令,可对数组进行切片

  • start 是普通数组的起始索引偏移;稀疏数组会跳过未设置的位置,不能简单理解为“第几个元素”
  • length 是最多取出的已有元素数量

这套切片写法用于普通数组,关联数组不应使用它。

替换

使用 "${array[@]/old/new}",对每个元素分别替换第一个匹配 old 的部分;old 是 Shell 模式。这只是展开结果,不会直接修改原数组。

  • array是数组名
  • old 是需要替换的模式
  • new 是替换后的内容

双斜杠 "${array[@]//old/new}" 会替换每个元素中所有匹配的部分。若只想修改特定元素,则直接赋值:array[1]=新值。

1
2
3
4
array=(114514 1919810)
replaced=("${array[@]//1/9}")
printf '%s\n' "${replaced[@]}"
#输出:994594、9999890(各占一行),原数组仍然保留