在 Linux 系统运维与 Shell 脚本开发中,数组、函数与正则表达式是提升脚本效率、简化复杂操作的三大核心工具。掌握它们不仅能让你摆脱重复冗余的代码,更能轻松应对日志分析、数据处理、批量任务等场景。本文将从基础概念入手,结合实战案例,带你一步步玩转这三大技术。
一、Linux 数组:让数据存储更有序
在 Shell 脚本中,数组是 “批量存储数据的容器”,支持字符串、数字等多种类型,尤其适合处理批量文件名、IP 地址、配置参数等场景。与逐个定义变量相比,数组能极大减少代码冗余,还支持灵活的增删改查操作。
1. 数组的定义与初始化
Shell 数组无需声明类型,直接通过 “键值对” 或 “列表” 形式定义,常见方式有两种:
-
列表式定义:适合一次性存储多个元素,元素间用空格分隔
bash
# 定义存储服务器IP的数组 server_ips=("192.168.1.10" "192.168.1.11" "192.168.1.12") # 定义存储日志文件名的数组 log_files=("a***ess.log" "error.log" "nginx.log") -
键值对定义:适合自定义索引(如非连续数字、字符串索引)
bash
# 用字符串索引定义“服务-端口”映射数组 declare -A service_ports # 声明关联数组(支持字符串索引) service_ports["nginx"]=80 service_ports["mysql"]=3306 service_ports["redis"]=6379
2. 数组的核心操作(实战常用)
数组的操作重点在于 “获取元素”“遍历元素” 和 “修改元素”,以下是高频场景的实现代码:
-
获取单个元素:通过
数组名[索引]调用,${数组名[@]}可获取所有元素bash
echo "第一个服务器IP:${server_ips[0]}" # 输出:192.168.1.10 echo "所有日志文件:${log_files[@]}" # 输出:a***ess.log error.log nginx.log echo "Redis端口:${service_ports["redis"]}" # 输出:6379 -
遍历数组(批量操作):结合
for循环实现批量处理,比如批量压缩日志bash
# 遍历日志文件数组,批量压缩7天前的日志 for file in ${log_files[@]}; do find /var/log -name "$file" -mtime +7 -exec gzip {} \; echo "已压缩日志:$file" done -
数组长度与追加元素:
${#数组名[@]}获取长度,数组名+=("新元素")追加bash
echo "服务器数量:${#server_ips[@]}" # 输出:3 # 追加新的服务器IP server_ips+=("192.168.1.13") echo "更新后服务器数量:${#server_ips[@]}" # 输出:4
二、Linux 函数:让脚本逻辑更简洁
函数是 “封装重复代码的模块”,比如脚本中多次用到的 “日志输出”“服务状态检查” 等逻辑,都可以封装成函数。这样不仅能减少代码重复,还能让脚本结构更清晰,后期维护更方便。
1. 函数的定义与调用
Shell 函数的定义格式非常灵活,核心是 “函数名 + 代码块”,调用时直接用函数名即可:
bash
# 定义“输出带时间戳的日志”函数
log_info() {
local timestamp=$(date "+%Y-%m-%d %H:%M:%S") # local声明局部变量,仅函数内有效
echo "[$timestamp] [INFO] $1" # $1 是函数的第一个参数
}
# 定义“检查服务是否运行”函数
check_service() {
local service_name=$1
# 用pgrep检查进程是否存在,0为存在,非0为不存在
if pgrep "$service_name" > /dev/null; then
log_info "$service_name 服务正在运行"
return 0 # 函数返回值(0表示成功)
else
log_info "$service_name 服务已停止"
return 1 # 非0表示失败
fi
}
# 调用函数
check_service "nginx" # 输出:[2025-09-01 10:30:00] [INFO] nginx 服务正在运行
check_service "mysql" # 输出:[2025-09-01 10:30:00] [INFO] mysql 服务正在运行
2. 函数的进阶用法(参数与返回值)
-
函数参数:通过
$1(第一个参数)、$2(第二个参数)...$@(所有参数)获取,比如批量检查多个服务:bash
# 批量检查多个服务 batch_check() { for service in "$@"; do # $@ 接收所有传入的服务名参数 check_service "$service" done } # 调用:同时检查nginx、mysql、redis batch_check "nginx" "mysql" "redis" -
函数返回值:Shell 函数默认返回 “最后一条命令的退出状态”(0 成功,非 0 失败),若需返回自定义值,可通过
echo输出,再用变量接收:bash
# 定义“计算文件行数”函数 count_lines() { local file_path=$1 if [ -f "$file_path" ]; then wc -l "$file_path" | awk '{print $1}' # 用awk提取行数并输出 else echo 0 # 文件不存在时返回0 fi } # 调用函数并接收返回值 a***ess_lines=$(count_lines "/var/log/nginx/a***ess.log") echo "a***ess.log 总行数:$a***ess_lines" # 输出:a***ess.log 总行数:12580
三、Linux 正则表达式:让文本处理更高效
正则表达式(简称 “正则”)是 “按规则匹配文本的工具”,在 Linux 中结合 grep、sed、awk 等命令,可轻松实现日志过滤、内容替换、数据提取等复杂操作。掌握正则,能让你从 “手动查找文本” 升级为 “自动化处理文本”。
1. 正则基础:常用元字符与匹配规则
正则的核心是 “元字符”(具有特殊含义的字符),以下是 Linux 中最常用的元字符及规则:
| 元字符 | 含义 | 示例 |
|---|---|---|
^ |
匹配行首 |
^ERROR 匹配以 “ERROR” 开头的行 |
$ |
匹配行尾 |
INFO$ 匹配以 “INFO” 结尾的行 |
. |
匹配任意单个字符 |
a.c 匹配 “abc”“a1c” 等 |
* |
匹配前一个字符 0 次或多次 |
ab* 匹配 “a”“ab”“abb” 等 |
[] |
匹配括号内任意一个字符 |
[0-9] 匹配任意数字 |
[^] |
匹配括号外任意一个字符 |
[^a-z] 匹配非小写字母 |
\d |
匹配数字(等价于 [0-9]) |
\d{3} 匹配 3 个连续数字 |
\b |
匹配单词边界 |
\buser\b 匹配独立的 “user” |
2. 正则实战:结合命令解决实际问题
正则的价值在于 “结合命令使用”,以下是运维中高频的实战场景:
-
场景 1:过滤日志中的错误信息
用grep结合正则,从 nginx 错误日志中提取 “500 错误” 的行:bash
# 过滤包含“500 Internal Server Error”的行,显示行号(-n) grep -n "500 Internal Server Error" /var/log/nginx/error.log # 进阶:过滤近1小时内的500错误(结合时间格式正则) grep -n "^$(date -d '-1 hour' +'%Y/%m/%d %H')" /var/log/nginx/error.log | grep "500" -
场景 2:批量替换配置文件内容
用sed结合正则,将所有服务器配置中的 “旧 IP” 替换为 “新 IP”:bash
# 替换server.conf中所有“192.168.1.10”为“192.168.1.20”(-i 表示直接修改文件) sed -i 's/192.168.1.10/192.168.1.20/g' /etc/server.conf # 进阶:替换所有以“port = ”开头的行,将端口改为8080 sed -i 's/^port = .*/port = 8080/' /etc/app.conf -
场景 3:提取日志中的 IP 地址
用awk结合正则,从 a***ess.log 中提取所有访问 IP,并统计出现次数(按次数排序):bash
# 提取IP(日志中IP在第一列,用空格分隔),统计次数,按次数降序排列 awk '{print $1}' /var/log/nginx/a***ess.log | grep -E '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$' | sort | uniq -c | sort -nr # 说明:grep -E 启用扩展正则,匹配IP格式;uniq -c 统计次数;sort -nr 按数字降序
四、三者结合:编写高效运维脚本
单独使用数组、函数、正则已能解决很多问题,而将三者结合,能编写更强大的自动化脚本。以下是一个 “批量检查服务器服务状态” 的综合案例:
bash
#!/bin/bash
# 脚本功能:批量检查多台服务器的指定服务状态,并输出带时间戳的日志
# 1. 定义数组:存储服务器IP和需要检查的服务
server_ips=("192.168.1.10" "192.168.1.11" "192.168.1.12")
check_services=("nginx" "mysql" "redis")
# 2. 定义函数:输出带时间戳的日志
log_info() {
local timestamp=$(date "+%Y-%m-%d %H:%M:%S")
echo "[$timestamp] [INFO] $1"
}
# 3. 定义函数:检查单台服务器的单个服务(通过SSH远程执行)
check_remote_service() {
local server_ip=$1
local service=$2
# 用正则匹配SSH连接结果:若包含“active (running)”则服务正常
ssh -o ConnectTimeout=5 "$server_ip" "systemctl status $service" 2>&1 | grep -qE 'active \(running\)'
if [ $? -eq 0 ]; then
log_info "$server_ip - $service 服务正常"
else
log_info "$server_ip - $service 服务异常(或SSH连接失败)"
fi
}
# 4. 主逻辑:遍历数组,批量检查
log_info "开始批量检查服务器服务状态"
for ip in ${server_ips[@]}; do
log_info "================ 检查服务器:$ip ================"
for service in ${check_services[@]}; do
check_remote_service "$ip" "$service"
done
done
log_info "批量检查完成"
脚本执行效果如下:
plaintext
[2025-09-01 11:00:00] [INFO] 开始批量检查服务器服务状态
[2025-09-01 11:00:00] [INFO] ================ 检查服务器:192.168.1.10 ================
[2025-09-01 11:00:01] [INFO] 192.168.1.10 - nginx 服务正常
[2025-09-01 11:00:02] [INFO] 192.168.1.10 - mysql 服务正常
[2025-09-01 11:00:03] [INFO] 192.168.1.10 - redis 服务正常
[2025-09-01 11:00:03] [INFO] ================ 检查服务器:192.168.1.11 ================
[2025-09-01 11:00:08] [INFO] 192.168.1.11 - nginx 服务异常(或SSH连接失败)
...
总结
数组让数据管理更有序,函数让代码逻辑更简洁,正则让文本处理更高效 —— 这三者是 Linux 脚本开发的 “三驾马车”。从简单的批量操作,到复杂的自动化运维脚本,掌握它们能让你的工作效率大幅提升。建议从 “模仿案例” 开始,尝试将日常重复的操作(如日志清理、服务检查)写成脚本,逐步积累实战经验。如果在实践中遇到具体场景(如复杂日志提取、多维度数组处理),可以进一步深入探索进阶用法,让脚本更贴合实际需求。