Skip to content

数组

数组定义

普通数组

bash
# 定义数组
arr=("apple" "banana" "orange")

# 逐个定义
arr[0]="apple"
arr[1]="banana"
arr[2]="orange"

# 混合定义
arr=("apple" "banana")
arr[2]="orange"
arr[3]="grape"

关联数组(Bash 4+)

bash
# 声明关联数组
declare -A arr

# 定义关联数组
arr["name"]="张三"
arr["age"]=25
arr["city"]="北京"

数组访问

访问单个元素

bash
arr=("apple" "banana" "orange")

# 访问第一个元素(索引从 0 开始)
echo ${arr[0]}  # 输出:apple

# 访问第二个元素
echo ${arr[1]}  # 输出:banana

# 访问最后一个元素
echo ${arr[-1]}  # 输出:orange

访问所有元素

bash
arr=("apple" "banana" "orange")

# 访问所有元素
echo ${arr[@]}  # 输出:apple banana orange

# 访问所有元素(每个元素作为独立字符串)
echo "${arr[@]}"  # 输出:apple banana orange

# 访问所有元素(作为一个字符串)
echo "${arr[*]}"  # 输出:apple banana orange

访问数组长度

bash
arr=("apple" "banana" "orange")

# 获取数组长度
echo ${#arr[@]}  # 输出:3

# 获取单个元素长度
echo ${#arr[0]}  # 输出:5

数组遍历

遍历所有元素

bash
arr=("apple" "banana" "orange")

# 方式一:使用 for 循环
for item in "${arr[@]}"; do
    echo "$item"
done

# 方式二:使用索引
for i in "${!arr[@]}"; do
    echo "索引 $i: ${arr[$i]}"
done

遍历关联数组

bash
declare -A arr
arr["name"]="张三"
arr["age"]=25
arr["city"]="北京"

# 遍历所有键
for key in "${!arr[@]}"; do
    echo "$key: ${arr[$key]}"
done

数组操作

添加元素

bash
arr=("apple" "banana")

# 添加元素到末尾
arr+=("orange")
arr+=("grape")

# 添加元素到指定位置
arr[2]="pear"

# 使用索引添加
arr[${#arr[@]}]="peach"

删除元素

bash
arr=("apple" "banana" "orange" "grape")

# 删除指定索引的元素
unset arr[1]

# 删除整个数组
unset arr

# 删除关联数组的元素
declare -A arr
arr["name"]="张三"
unset arr["name"]

修改元素

bash
arr=("apple" "banana" "orange")

# 修改元素
arr[0]="pear"
arr[1]="peach"

# 修改最后一个元素
arr[-1]="grape"

数组切片

提取子数组

bash
arr=("a" "b" "c" "d" "e")

# 从索引 1 开始,提取 3 个元素
echo ${arr[@]:1:3}  # 输出:b c d

# 从索引 2 开始到结尾
echo ${arr[@]:2}    # 输出:c d e

# 提取最后 2 个元素
echo ${arr[@]: -2}  # 输出:d e

替换元素

bash
arr=("apple" "banana" "orange")

# 替换第一个匹配
echo ${arr[@]/banana/pear}  # 输出:apple pear orange

# 替换所有匹配
echo ${arr[@]//a/A}         # 输出:Apple bAnAnge OrAnge

数组排序

使用 sort 命令

bash
arr=("orange" "apple" "banana" "grape")

# 排序
sorted=($(echo "${arr[@]}" | tr ' ' '\n' | sort))

# 输出排序后的数组
echo "${sorted[@]}"  # 输出:apple banana grape orange

数字数组排序

bash
arr=("3" "1" "4" "1" "5")

# 数字排序
sorted=($(echo "${arr[@]}" | tr ' ' '\n' | sort -n))

# 输出排序后的数组
echo "${sorted[@]}"  # 输出:1 1 3 4 5

数组查找

检查元素是否存在

bash
arr=("apple" "banana" "orange")

# 检查元素是否存在
if [[ " ${arr[@]} " =~ " banana " ]]; then
    echo "banana 存在"
fi

# 使用函数检查
contains_element() {
    local e match="$1"
    shift
    for e; do [[ "$e" == "$match" ]] && return 0; done
    return 1
}

if contains_element "banana" "${arr[@]}"; then
    echo "banana 存在"
fi

查找元素索引

bash
arr=("apple" "banana" "orange")

# 查找元素索引
get_index() {
    local element="$1"
    shift
    local arr=("$@")
    for i in "${!arr[@]}"; do
        if [[ "${arr[$i]}" == "$element" ]]; then
            echo $i
            return
        fi
    done
    echo -1
}

index=$(get_index "banana" "${arr[@]}")
echo "banana 的索引: $index"  # 输出:1

数组合并

合并两个数组

bash
arr1=("apple" "banana")
arr2=("orange" "grape")

# 合并数组
merged=("${arr1[@]}" "${arr2[@]}")

echo "${merged[@]}"  # 输出:apple banana orange grape

数组去重

bash
arr=("apple" "banana" "apple" "orange" "banana")

# 去重
unique=($(echo "${arr[@]}" | tr ' ' '\n' | sort -u | tr '\n' ' '))

echo "${unique[@]}"  # 输出:apple banana orange

数组实用函数

检查是否为数组

bash
is_array() {
    local var="$1"
    [[ "$(declare -p $var 2>/dev/null)" =~ "declare -a" ]]
}

# 使用
arr=("apple" "banana")
if is_array arr; then
    echo "是数组"
fi

数组反转

bash
reverse_array() {
    local arr=("$@")
    local len=${#arr[@]}
    for ((i=len-1; i>=0; i--)); do
        echo "${arr[$i]}"
    done
}

# 使用
arr=("a" "b" "c" "d")
reversed=($(reverse_array "${arr[@]}"))
echo "${reversed[@]}"  # 输出:d c b a

数组交集

bash
intersection() {
    local arr1=("$1")
    shift
    local arr2=("$@")
    local result=()
    for item in "${arr1[@]}"; do
        if [[ " ${arr2[@]} " =~ " $item " ]]; then
            result+=("$item")
        fi
    done
    echo "${result[@]}"
}

# 使用
arr1=("apple" "banana" "orange")
arr2=("banana" "grape" "apple")
intersect=($(intersection "${arr1[@]}" "${arr2[@]}"))
echo "${intersect[@]}"  # 输出:apple banana

实用示例

示例1:读取文件到数组

bash
#!/bin/bash

# 读取文件到数组
read_file_to_array() {
    local file="$1"
    local -a arr
    while IFS= read -r line; do
        arr+=("$line")
    done < "$file"
    echo "${arr[@]}"
}

# 使用
arr=($(read_file_to_array "file.txt"))
for line in "${arr[@]}"; do
    echo "$line"
done

示例2:命令行参数数组

bash
#!/bin/bash

# 获取所有参数
args=("$@")

# 输出所有参数
echo "参数个数: ${#args[@]}"
for i in "${!args[@]}"; do
    echo "参数 $((i+1)): ${args[$i]}"
done

示例3:数组统计

bash
#!/bin/bash

# 数组统计
arr=("apple" "banana" "orange" "apple" "banana" "apple")

# 统计每个元素出现的次数
declare -A count
for item in "${arr[@]}"; do
    ((count[$item]++))
done

# 输出统计结果
for item in "${!count[@]}"; do
    echo "$item: ${count[$item]}"
done

示例4:数组过滤

bash
#!/bin/bash

# 数组过滤
filter_array() {
    local pattern="$1"
    shift
    local arr=("$@")
    local result=()
    for item in "${arr[@]}"; do
        if [[ "$item" =~ $pattern ]]; then
            result+=("$item")
        fi
    done
    echo "${result[@]}"
}

# 使用
arr=("apple1" "banana" "orange2" "grape3")
filtered=($(filter_array "^[a-z]+[0-9]$" "${arr[@]}"))
echo "${filtered[@]}"  # 输出:apple1 orange2 grape3

最佳实践

1. 使用引号

bash
# 好的做法
for item in "${arr[@]}"; do
    echo "$item"
done

# 不好的做法
for item in ${arr[@]}; do
    echo $item
done

2. 检查数组长度

bash
# 好的做法
if [ ${#arr[@]} -gt 0 ]; then
    echo "数组不为空"
fi

# 不好的做法
for item in "${arr[@]}"; do
    echo "$item"
done

3. 使用局部变量

bash
# 好的做法
func() {
    local arr=("a" "b" "c")
    echo "${arr[@]}"
}

# 不好的做法
func() {
    arr=("a" "b" "c")
    echo "${arr[@]}"
}

总结

数组操作的关键点:

  1. 定义数组:arr=("元素1" "元素2" "元素3")
  2. 访问元素:${arr[索引]}
  3. 访问所有元素:${arr[@]}
  4. 获取长度:${#arr[@]}
  5. 添加元素:arr+=("新元素")
  6. 删除元素:unset arr[索引]
  7. 数组切片:${arr[@]:起始:长度}
  8. 遍历数组:for item in "${arr[@]}"; do ... done

下一节我们将学习运算符的使用。