Skip to content

数组操作

本节介绍 Shell 数组的进阶操作,包括遍历、过滤、排序和关联数组的高级用法。

数组复制

bash
original=(1 2 3 4 5)

# 完整复制
copy=("${original[@]}")

# 验证
echo "${copy[@]}"   # 1 2 3 4 5

数组合并

bash
arr1=(a b c)
arr2=(d e f)

# 合并两个数组
merged=("${arr1[@]}" "${arr2[@]}")
echo "${merged[@]}"   # a b c d e f

添加与删除元素

bash
arr=(a b c)

# 追加元素
arr+=(d e)
echo "${arr[@]}"   # a b c d e

# 删除指定元素(通过 unset)
unset arr[2]              # 删除索引 2(c)
echo "${arr[@]}"          # a b d e(索引出现空洞)
echo "${arr[*]}"          # a b d e

# 重建数组(消除空洞)
arr=("${arr[@]}")
echo "${!arr[@]}"         # 0 1 2 3(连续索引)

# 删除最后一个元素
unset 'arr[-1]'

数组切片

bash
arr=(a b c d e f g)

# 从索引 2 开始取 3 个元素
echo "${arr[@]:2:3}"   # c d e

# 从索引 4 开始到末尾
echo "${arr[@]:4}"     # e f g

数组遍历

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

# 遍历元素
for item in "${arr[@]}"; do
    echo "$item"
done

# 遍历索引
for i in "${!arr[@]}"; do
    echo "[$i] ${arr[$i]}"
done

# C 风格遍历
for (( i=0; i<${#arr[@]}; i++ )); do
    echo "[$i] ${arr[$i]}"
done

数组过滤

bash
#!/bin/bash

arr=(1 2 3 4 5 6 7 8 9 10)

# 过滤出偶数
evens=()
for n in "${arr[@]}"; do
    (( n % 2 == 0 )) && evens+=("$n")
done
echo "偶数:${evens[@]}"   # 2 4 6 8 10

# 过滤包含特定字符串的元素
words=("apple" "apricot" "banana" "avocado")
filtered=()
for w in "${words[@]}"; do
    [[ "$w" == a* ]] && filtered+=("$w")
done
echo "以 a 开头:${filtered[@]}"   # apple apricot avocado

数组排序

bash
#!/bin/bash

arr=(3 1 4 1 5 9 2 6)

# 升序排序
sorted=($(echo "${arr[@]}" | tr ' ' '\n' | sort -n))
echo "升序:${sorted[@]}"   # 1 1 2 3 4 5 6 9

# 降序排序
sorted_desc=($(echo "${arr[@]}" | tr ' ' '\n' | sort -rn))
echo "降序:${sorted_desc[@]}"

# 字符串数组排序
words=("banana" "apple" "cherry")
sorted_words=($(echo "${words[@]}" | tr ' ' '\n' | sort))
echo "排序:${sorted_words[@]}"   # apple banana cherry

数组去重

bash
#!/bin/bash

arr=(1 2 3 2 4 3 5 1)

# 使用关联数组去重
declare -A seen
unique=()
for item in "${arr[@]}"; do
    if [[ -z "${seen[$item]+x}" ]]; then
        unique+=("$item")
        seen[$item]=1
    fi
done
echo "去重:${unique[@]}"   # 1 2 3 4 5

关联数组(字典)操作

bash
#!/bin/bash

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

# 访问
echo "${user["name"]}"

# 遍历键值对
for key in "${!user[@]}"; do
    echo "$key = ${user[$key]}"
done

# 检查键是否存在
if [[ -v user["name"] ]]; then
    echo "name 键存在"
fi

# 删除键
unset user["age"]
echo "删除 age 后:${!user[@]}"

# 获取所有键
echo "所有键:${!user[@]}"

# 获取所有值
echo "所有值:${user[@]}"

实用示例

实现栈(Stack)

bash
#!/bin/bash

stack=()

push() { stack+=("$1"); }
pop() {
    [ ${#stack[@]} -eq 0 ] && return 1
    echo "${stack[-1]}"
    unset 'stack[-1]'
}
peek() { echo "${stack[-1]}"; }

push "a"; push "b"; push "c"
echo "栈顶:$(peek)"     # c
echo "弹出:$(pop)"      # c
echo "当前栈:${stack[@]}"  # a b

实现队列(Queue)

bash
#!/bin/bash

queue=()

enqueue() { queue+=("$1"); }
dequeue() {
    [ ${#queue[@]} -eq 0 ] && return 1
    echo "${queue[0]}"
    queue=("${queue[@]:1}")
}

enqueue "first"
enqueue "second"
enqueue "third"
echo "出队:$(dequeue)"   # first
echo "当前队列:${queue[@]}"   # second third

统计词频

bash
#!/bin/bash

text="apple banana apple cherry banana apple"
declare -A freq

for word in $text; do
    (( freq[$word]++ ))
done

for word in "${!freq[@]}"; do
    echo "$word: ${freq[$word]}"
done
# apple: 3
# banana: 2
# cherry: 1