数组:索引数组、关联数组 (Arrays)
章节概述
本章讲解 Bash 数组的两种类型:索引数组(整数下标)和关联数组(字符串键),以及数组的声明、赋值、遍历、切片、追加等操作。通过与 C 数组的对比,理解 Bash 数组的动态特性和使用限制。
核心理念:Bash 数组是动态的、稀疏的、无类型的——你可以随时添加元素,下标可以不连续,同一个数组可以混合存储字符串和数字。
第1节:索引数组声明与赋值
# 方式1:直接赋值
fruits=("apple" "banana" "cherry")
# 方式2:逐个赋值
colors[0]="red"
colors[1]="green"
colors[2]="blue"
# 方式3:声明后赋值
declare -a nums
nums=(10 20 30 40 50)
# 访问元素
echo ${fruits[0]} # apple
echo ${fruits[2]} # cherry
# 修改元素
fruits[1]="blueberry"稀疏数组:
# 下标可以不连续
sparse[0]="zero"
sparse[5]="five"
sparse[10]="ten"
echo ${#sparse[@]} # 3(只有3个元素)C 数组对比:
// C:固定大小、固定类型、连续内存
int nums[5] = {10, 20, 30, 40, 50};
char *fruits[] = {"apple", "banana", "cherry"};
// 访问
printf("%d\n", nums[0]); // 10
printf("%s\n", fruits[1]); // banana# Bash:动态、无类型、可稀疏
nums=(10 20 30 40 50)
fruits=("apple" "banana" "cherry")
mixed=("hello" 42 3.14) # 可混合类型
echo ${nums[0]} # 10
echo ${fruits[1]} # banana
echo ${mixed[2]} # 3.14第2节:数组长度与元素
arr=("a" "b" "c" "d" "e")
echo ${#arr[@]} # 5(元素个数)
echo ${#arr[0]} # 1(第一个元素的长度)获取所有元素:
arr=("a" "b" "c")
# ${arr[@]} 和 ${arr[*]} 的区别
echo ${arr[@]} # a b c(分别引用)
echo ${arr[*]} # a b c(作为整体)
# 在 for 循环中必须用 "${arr[@]}"(加引号)
for item in "${arr[@]}"; do
echo "$item"
done{arr[*]}:
| 语法 | 含义 | 用途 |
|---|---|---|
${arr[@]} | 各元素独立 | for 循环、传参 |
${arr[*]} | 拼接为一个字符串 | 统计、打印 |
arr=("hello world" "foo bar")
# 加引号的区别
for x in "${arr[@]}"; do echo "[$x]"; done
# [hello world]
# [foo bar]
for x in ${arr[@]}; do echo "[$x]"; done
# [hello]
# [world]
# [foo]
# [bar]第3节:数组遍历
# 遍历值
arr=("apple" "banana" "cherry")
for fruit in "${arr[@]}"; do
echo "$fruit"
done
# 遍历索引
for i in "${!arr[@]}"; do
echo "索引 $i: ${arr[$i]}"
done
# C 风格遍历
for ((i=0; i<${#arr[@]}; i++)); do
echo "${arr[$i]}"
done第4节:数组追加与删除
arr=("a" "b" "c")
# 追加元素
arr+=("d" "e")
echo ${arr[@]} # a b c d e
# 删除元素(留下空洞)
unset arr[1] # 删除 "b"
echo ${arr[@]} # a c d e
echo ${#arr[@]} # 4追加 vs 赋值:
arr=(1 2 3)
arr+=(4 5) # 追加
echo ${arr[@]} # 1 2 3 4 5
arr=(1 2 3)
arr[10]=100 # 赋值到指定位置
echo ${arr[@]} # 1 2 3 100(稀疏)
echo ${#arr[@]} # 4第5节:数组切片
arr=("a" "b" "c" "d" "e")
echo ${arr[@]:1:3} # b c d(从索引1取3个)
echo ${arr[@]:2} # c d e(从索引2到末尾)
echo ${arr[@]::3} # a b c(前3个)切片语法:
| 语法 | 说明 |
|---|---|
${arr[@]:pos} | 从 pos 到末尾 |
${arr[@]:pos:len} | 从 pos 取 len 个 |
${arr[@]::len} | 前 len 个 |
第6节:关联数组(Bash 4+)
# 必须用 declare -A 声明
declare -A ages
ages[alice]=25
ages[bob]=30
ages[charlie]=35
# 声明时赋值
declare -A capitals=(
[China]="Beijing"
[Japan]="Tokyo"
[France]="Paris"
)
echo ${ages[alice]} # 25
echo ${capitals[Japan]} # Tokyo关联数组遍历:
declare -A scores=(
[math]=95
[english]=88
[science]=92
)
# 遍历键
for subject in "${!scores[@]}"; do
echo "$subject: ${scores[$subject]}"
done
# 遍历值
for score in "${scores[@]}"; do
echo "$score"
done索引 vs 关联数组:
| 特性 | 索引数组 | 关联数组 |
|---|---|---|
| 声明 | arr=() 或 declare -a | declare -A map |
| 下标 | 整数 | 字符串 |
| 顺序 | 按索引 | 按哈希(无序) |
| Bash 版本 | 所有版本 | 4.0+ |
第7节:数组作为函数参数
# 传递数组给函数
print_array() {
local arr=("$@")
for item in "${arr[@]}"; do
echo "$item"
done
}
fruits=("apple" "banana" "cherry")
print_array "${fruits[@]}"数组切片传参:
# 传递部分数组
subarray=("${fruits[@]:1:2}")
print_array "${subarray[@]}" # banana cherry第8节:实战 —— 简易学生管理系统
#!/usr/bin/env bash
declare -A students
students[1001]="Alice:95"
students[1002]="Bob:88"
students[1003]="Charlie:92"
echo "学号 姓名 成绩"
echo "---- ---- ----"
for id in $(echo "${!students[@]}" | tr ' ' '\n' | sort); do
IFS=':' read -r name score <<< "${students[$id]}"
printf "%-6s %-8s %s\n" "$id" "$name" "$score"
done第9节:课后练习
- 创建关联数组存储 5 种水果及其价格
- 编写函数接收数组参数并返回所有偶数元素
- 实现简单的键值对配置文件解析器
相关章节: