Day 8:Shell数组与哈希完全指南:从“青铜“到“王者“的进化之路
目录
- 一、索引数组:你的第一个"集合容器"
- 1. 基础操作四连击
- 2. 实用技巧:灵活初始化
- 二、关联数组:让数据拥有"名字"
- 1. 哈希表声明与使用
- 2. 高级遍历技巧
- 三、避坑指南:数组操作的"暗礁险滩"
- 1. 稀疏数组陷阱
- 2. 含空格元素的正确处理
- 3. 数组复制陷阱
- 四、实战:用哈希解析配置文件
- 五、终极挑战:单词频率统计器
- 六、性能优化:数组 vs 外部命令
- 1. 大数据集处理对比
- 2. 内存优化技巧
- 课后升级挑战
开篇:当变量不再孤单
想象你是个班主任:
- 普通变量:只能记住一个学生名字(“张三”)
- 数组变量:能记住全班名单([“张三”,“李四”,“王五”])
- 哈希变量:还能记住每个学生的学号({“张三”=>101, “李四”=>102})
今天我们就让Shell变量突破次元壁,解锁集合类型的超能力!
一、索引数组:你的第一个"集合容器"
1. 基础操作四连击
# 声明数组(Shell最奇葩的语法!)
fruits=("苹果" "香蕉" "橙子" "草莓")# 访问元素(从0开始)
echo ${fruits[1]} # 输出:香蕉# 修改元素
fruits[0]="红苹果"# 获取数组长度
echo "共有 ${#fruits[@]} 种水果"
2. 实用技巧:灵活初始化
# 从命令结果创建数组
processes=($(ps -ef | awk '{print $2}'))# 序列生成(Bash 4.0+)
mapfile -t lines < /etc/passwd # 按行读取到数组
nums=({1..10..2}) # 生成1 3 5 7 9
二、关联数组:让数据拥有"名字"
1. 哈希表声明与使用
# 必须先声明(Bash 4.0+)
declare -A student_scores# 添加键值对
student_scores=(["张三"]=90["李四"]=85["王五"]=78
)# 动态添加
student_scores["赵六"]=92# 查询
echo "张三的成绩:${student_scores["张三"]}"
2. 高级遍历技巧
# 遍历所有键
for name in "${!student_scores[@]}"; doecho "$name : ${student_scores[$name]}"
done# 按值排序输出
for k in $(echo ${!student_scores[@]} | tr ' ' '\n' | sort); doecho "$k ${student_scores[$k]}"
done
三、避坑指南:数组操作的"暗礁险滩"
1. 稀疏数组陷阱
arr=([0]="a" [3]="d") # 中间有空位
echo "元素个数:${#arr[@]}" # 输出2不是4!
2. 含空格元素的正确处理
# 错误示范
files=($(ls *.txt)) # 文件名含空格会分裂# 正确做法(IFS+mapfile)
IFS=$'\n' mapfile -t files < <(find . -name "*.txt")
3. 数组复制陷阱
arr1=(1 2 3)
arr2=("${arr1[@]}") # 正确复制方式
arr3=${arr1[@]} # 错误!变成字符串
四、实战:用哈希解析配置文件
#!/bin/bash
declare -A configparse_config() {while IFS='=' read -r key value; do[[ $key == [* ]] || continue # 跳过注释config["${key%%[[:space:]]*}"]="${value#*[[:space:]]}"done < "app.conf"
}# 示例配置文件内容:
# [database]
# host = 127.0.0.1
# port = 3306parse_config
echo "数据库地址:${config[host]}:${config[port]}"
五、终极挑战:单词频率统计器
#!/bin/bash
declare -A word_count# 统计函数
count_words() {tr '[:upper:]' '[:lower:]' | # 统一小写tr -cs '[:alpha:]' '\n' | # 保留字母生成单词列表sort |uniq -c | # 统计频次while read count word; doword_count["$word"]=$countdone
}# 分析文本
echo "The quick brown fox jumps over the lazy dog" | count_words# 输出结果
for word in "${!word_count[@]}"; doprintf "%-10s %d\n" "$word" "${word_count[$word]}"
done | sort -k2nr # 按频次降序
输出示例:
the 2
fox 1
dog 1
...(其他单词)
六、性能优化:数组 vs 外部命令
1. 大数据集处理对比
# 方式1:纯数组操作(更快)
for ((i=0; i<10000; i++)); doarr[$i]=$RANDOM
done# 方式2:调用外部命令(更慢)
for i in {1..10000}; doarr[$i]=$(awk 'BEGIN{print rand()}')
done
2. 内存优化技巧
# 大数组分批处理
batch_size=1000
for ((i=0; i<${#huge_array[@]}; i+=batch_size)); dobatch=("${huge_array[@]:$i:$batch_size}")process_batch "${batch[@]}"
done
课后升级挑战
任务:开发升级版词频统计工具
- ✅ 支持从文件/管道/stdin多方式输入
- ✅ 忽略常见停用词(the,a,an等)
- ✅ 生成词云HTML可视化
示例效果:
$ ./wordfreq.sh < novel.txt | head -5
the 1245
love 890
time 765
...