Shell 数组

《Shell 数组》

🧮 学习目标

  1. 掌握 Shell 中数组的定义、访问、遍历与操作方法。
  2. 理解索引数组和关联数组的区别,学会在不同场景下使用合适的数组类型。
  3. 学会在阿里云 Ubuntu ECS 上编写带数组的脚本,用于服务管理、日志分析、批量处理等实际场景。
  4. 掌握数组的常用操作:追加元素、删除元素、获取长度、切片、排序等。
  5. 能结合 for 循环、条件判断等结构实现复杂逻辑。

🧠 核心重点(表格提炼)

内容 示例 说明
定义数组 arr=(a b c) 使用括号赋值
访问元素 ${arr[0]} 获取第一个元素
遍历数组 for item in "${arr[@]}" 推荐用法
获取长度 ${#arr[@]} 获取数组元素个数
追加元素 arr+=(d) 在末尾添加新元素
删除元素 unset arr[1] 可删除指定索引
切片操作 ${arr[@]:1:2} 获取从第1个开始的2个元素
关联数组 declare -A map 键值对存储(bash 4+)

🔍 详细讲解

1. Shell 中有“数组”吗?🧐

是的!虽然 Shell 不是真正的编程语言,但它支持数组这种数据结构,能帮助我们更高效地处理多个变量或列表型数据。

📌 为什么重要?

  • 处理多个文件、服务名、IP 地址时非常方便。
  • 提高脚本灵活性,避免重复代码。
  • 是构建自动化运维工具的基础。

📌 注意:

  • Shell 的数组是字符串数组,不支持嵌套。
  • 默认是索引数组(数字下标),也可使用关联数组(键值对)。

2. Shell 数组的基本操作 📝

✅ 1. 定义数组

services=("nginx" "mysql" "redis")

📌 也可以跨行写:

files=(
    "/etc/passwd"
    "/etc/group"
    "/etc/shadow"
)

✅ 2. 访问数组元素

echo "${services[0]}"   # 输出 nginx
echo "${services[1]}"   # 输出 mysql

📌 注意:

  • 数组索引从 0 开始。
  • 使用 {} 包裹变量更安全。

✅ 3. 获取数组长度

echo "服务数量:${#services[@]}"

📌 输出:

服务数量:3

✅ 4. 遍历数组(推荐方式)

for service in "${services[@]}"; do
    echo "正在检查服务:$service"
done

📌 说明:

  • "${services[@]}" 是标准遍历方式,保留空格和特殊字符。
  • 不建议使用 $*,它会把整个数组当作一个字符串。

✅ 5. 追加元素到数组末尾

services+=("php-fpm")

📌 结果:

nginx mysql redis php-fpm

✅ 6. 删除数组中的某个元素

unset services[2]   # 删除 redis

📌 注意:

  • 删除后索引不会重新排列,可以使用 reindex 或直接跳过空位。

✅ 7. 切片操作(获取子数组)

echo "${services[@]:1:2}"

📌 说明:

  • 从索引 1 开始取 2 个元素。
  • 输出为:mysql php-fpm

✅ 8. 替换元素内容

services[2]="mariadb"

📌 替换前: redis
📌 替换后: mariadb


3. 实战案例:ECS 上的数组应用 🛠️

场景一:批量重启服务并检查状态 ⚙️

你想编写一个脚本,自动重启一组服务,并检查它们的状态是否正常。

✅ 示例脚本 restart_services.sh

#!/bin/bash
# 服务列表
services=("nginx" "mysql" "redis")

# 重启每个服务
for service in "${services[@]}"; do
    echo "🔄 正在重启 $service..."
    sudo systemctl restart "$service"

    # 检查状态
    if systemctl is-active --quiet "$service"; then
        echo "✅ $service 重启成功"
    else
        echo "❌ $service 启动失败"
    fi
done

📌 运行方式:

chmod +x restart_services.sh
./restart_services.sh

场景二:动态生成备份文件路径列表 🗂️

你想将多个目录打包备份,但目录名称可能包含空格或特殊字符。

✅ 示例脚本 backup_dirs.sh

#!/bin/bash
dirs=("/home/ubuntu/logs" "/var/www/html" "/etc/nginx")

for dir in "${dirs[@]}"; do
    if [ -d "$dir" ]; then
        echo "📦 正在备份:$dir"
        tar -czf "/home/ubuntu/backup_$(basename "$dir").tar.gz" "$dir"
    else
        echo "⚠️ 目录不存在:$dir"
    fi
done

📌 优点:

  • 支持含空格路径
  • 动态生成备份文件名

场景三:使用关联数组保存配置信息 🎛️

你希望将一些配置参数以键值对形式保存,便于读取和修改。

✅ 示例脚本 config_loader.sh

#!/bin/bash
# bash 4+ 才支持关联数组
declare -A config
config["db_host"]="localhost"
config["db_user"]="root"
config["db_pass"]="secret"

echo "数据库地址:${config["db_host"]}"
echo "用户名:${config["db_user"]}"

📌 输出:

数据库地址:localhost
用户名:root

📌 注意:

  • 必须使用 bash 执行,不能使用 sh
  • 兼容性不如索引数组好

🧰 小贴士(进阶技巧)🔖

技巧 说明
mapfile / readarray 快速将命令输出存入数组
sort / uniq 对数组排序或去重
IFS=\n' 设置分隔符按行分割
eval 构建动态数组名(慎用)
reindex 手动重建数组索引
+=() 批量追加多个元素
unset array[@] 清空整个数组

📌 示例:读取文件每一行为数组元素

mapfile -t lines < <(cat /etc/passwd)
for line in "${lines[@]}"; do
    echo "$line"
done

📌 注意事项与安全建议

项目 建议
使用双引号包裹所有变量引用 "$item"
不要使用 eval 构造数组名 易引发安全问题
对输入数组做校验 防止空值或非法路径
删除元素后记得处理索引 避免出现“空洞”
使用 mapfile 时注意内存占用 大文件可能导致性能下降
脚本中尽量使用局部数组 避免全局污染

🧩 附录:Shell 数组实战模板(推荐使用)

#!/bin/bash
# 脚本名称:check_files.sh
# 功能描述:检查多个文件是否存在
# 作者:Linux 专家
# 日期:2025-06-17

files=(
    "/etc/passwd"
    "/etc/group"
    "/etc/nonexistent"
)

for file in "${files[@]}"; do
    if [ -f "$file" ]; then
        echo "✅ 文件存在:$file"
    else
        echo "❌ 文件不存在:$file"
    fi
done

📌 运行效果:

✅ 文件存在:/etc/passwd
✅ 文件存在:/etc/group
❌ 文件不存在:/etc/nonexistent

🎯 总结一句话:

“Shell 数组就像一个智能收纳盒📦 —— 它能帮你整齐有序地管理多个变量,是你编写复杂脚本、提升自动化效率的关键武器!”

是否继续下一章?我将继续输出:

  • 《Shell 条件判断与流程控制》⚙️
  • 《Shell 函数与模块化编程》📦
  • 《Shell 字符串操作与正则表达式》🔤

请告诉我你想深入的方向吧!🚀

posted @ 2023-04-02 21:20  红尘过客2022  阅读(36)  评论(0)    收藏  举报