当前位置: 首页 > news >正文

函数,数组与正则表达式

Bash 进阶实战:函数、数组与正则表达式全解析

在 Linux 系统管理和自动化运维中,Bash 脚本是不可或缺的工具。掌握函数、数组和正则表达式这三大核心特性,能让你的脚本从“简单指令堆砌”升级为“模块化、高效化的工具”。本文将结合实例,详细讲解这三大特性的用法,帮你夯实 Bash 进阶基础。

一、Bash 自定义函数:让代码更模块化

函数的核心价值是“代码复用”——把重复执行的逻辑封装成独立模块,既减少冗余,又便于维护。Bash 中函数的定义和调用都非常简洁,且支持参数传递与返回值处理。

1.1 函数的定义格式

Bash 函数有两种常用定义方式,推荐使用第一种(结构更清晰):

# 方式1:标准格式(推荐)
function 函数名() {命令序列          # 函数体:可包含普通命令、流程控制(if/for等)
}# 方式2:简化格式(省略 function 关键字)
函数名() {命令序列
}

注意事项

  • 函数名需符合“字母/数字/下划线”规则,且不能以数字开头(如 sum1 合法,1sum 非法);
  • 函数体的 {} 前后需留空格(或换行),否则会语法报错;
  • 函数必须先定义,再调用(Bash 按顺序执行脚本,未定义的函数无法调用)。

1.2 函数的调用:直接用函数名

调用函数无需加括号,直接写“函数名”即可。如果需要传递参数,在函数名后紧跟参数(空格分隔)。

示例1:无参数函数
#!/bin/bash
# 定义一个打印欢迎信息的函数
function print_welcome() {echo "====================="echo " 欢迎使用 Bash 工具 "echo "====================="
}# 调用函数(直接写函数名)
print_welcome

执行结果:

=====================欢迎使用 Bash 工具 
=====================

1.3 函数的参数传递:用 $n 接收

Bash 函数不支持“形参定义”,而是通过 $n 接收外部传递的参数($1 表示第1个参数,$2 表示第2个,以此类推)。若参数序号≥10,需用 ${10} 表示(避免与 $1+0 混淆)。

示例2:带参数的求和函数
#!/bin/bash
# 定义求和函数:接收2个参数,计算并打印结果
function sum() {# $1 接收第一个参数,$2 接收第二个参数local num1=$1  # local 关键字:定义局部变量(仅函数内可用)local num2=$2# 验证输入是否为数字(避免计算报错)if ! [[ "$num1" =~ ^[0-9]+$ ]] || ! [[ "$num2" =~ ^[0-9]+$ ]]; thenecho "错误:请输入有效的正整数!"return 1  # 返回错误状态码(非0表示失败)filocal result=$((num1 + num2))echo "求和结果:$num1 + $num2 = $result"
}# 调用函数:传递2个参数(10和20)
sum 10 20
# 再次调用:传递其他参数
sum 30 45

执行结果:

求和结果:10 + 20 = 30
求和结果:30 + 45 = 75

1.4 函数的返回值:用 $? 接收

Bash 函数的返回值有两种常见形式:

  1. 状态码返回:用 return 数值 返回(仅支持 0-255 的整数,0 表示成功,非0表示失败),外部通过 $? 获取;
  2. 结果返回:若需返回字符串或大于255的数字,可在函数内用 echo 输出结果,外部通过 变量=$(函数名) 捕获。
示例3:两种返回值的用法
#!/bin/bash
# 1. 状态码返回:判断数字是否为偶数
function is_even() {local num=$1if (( num % 2 == 0 )); thenreturn 0  # 是偶数:返回成功状态码elsereturn 1  # 不是偶数:返回失败状态码fi
}# 2. 结果返回:计算数字的平方(返回大于255的结果)
function square() {local num=$1echo $((num * num))  # 用 echo 输出结果
}# 测试状态码返回
is_even 12
if [ $? -eq 0 ]; then  # $? 获取上一个命令(函数)的返回码echo "12 是偶数"
elseecho "12 是奇数"
fi# 测试结果返回
result=$(square 20)  # 捕获函数的 echo 输出
echo "20 的平方是:$result"

执行结果:

12 是偶数
20 的平方是:400

二、Bash 数组:高效管理批量数据

当需要处理“一组相关数据”(如服务器列表、日志文件名、配置参数)时,数组是最优选择。Bash 支持一维数组(不支持多维),可灵活实现数据的定义、读取、遍历和修改。

2.1 数组的定义:3种常见方式

Bash 数组无需声明长度,直接赋值即可,元素间用空格分隔。

# 方式1:直接定义(最常用)
array_name=(元素1 元素2 元素3 ...)
server_list=("192.168.1.10" "192.168.1.20" "192.168.1.30")  # 示例:服务器IP数组# 方式2:单独定义元素(指定索引)
array_name[索引]=元素
fruit[0]="apple"
fruit[1]="banana"
fruit[5]="orange"  # 索引可跳过,未赋值的索引默认为空# 方式3:从命令输出创建数组(将命令结果按空格分割为数组元素)
file_list=($(ls /home/user/docs))  # 示例:将 /home/user/docs 下的文件存入数组

2.2 数组的读取:获取单个或所有元素

数组元素的索引从 0 开始,通过 ${数组名[索引]} 读取单个元素;通过 ${数组名[@]}${数组名[*]} 读取所有元素。

示例4:读取数组元素
#!/bin/bash
# 定义数组
fruit=("apple" "banana" "orange" "grape")# 1. 读取指定索引的元素
echo "索引0的元素:${fruit[0]}"  # 输出 apple
echo "索引2的元素:${fruit[2]}"  # 输出 orange# 2. 读取所有元素(两种方式)
echo "所有元素(@):${fruit[@]}"  # 输出 apple banana orange grape
echo "所有元素(*):${fruit[*]}"  # 输出 apple banana orange grape# 3. 获取数组长度(元素个数)
echo "数组长度:${#fruit[@]}"  # 输出 4

2.3 数组的遍历:两种实用方式

遍历数组即“逐个处理元素”,常用 for 循环实现,根据场景选择不同方式。

方式1:直接遍历所有元素(推荐,无需关心索引)
#!/bin/bash
fruit=("apple" "banana" "orange" "grape")echo "方式1:遍历所有元素"
for item in "${fruit[@]}"; do  # 用 @ 确保元素包含空格时也能正确处理echo "水果:$item"
done
方式2:按索引遍历(需处理索引时用,如修改元素)
#!/bin/bash
fruit=("apple" "banana" "orange" "grape")
length=${#fruit[@]}  # 获取数组长度echo -e "\n方式2:按索引遍历"
for ((i=0; i<length; i++)); doecho "索引$i${fruit[$i]}"# 示例:修改元素(给每个水果加前缀)fruit[$i]="fresh_${fruit[$i]}"
done# 输出修改后的数组
echo -e "\n修改后的数组:${fruit[@]}"

执行结果:

方式1:遍历所有元素
水果:apple
水果:banana
水果:orange
水果:grape方式2:按索引遍历
索引0:apple
索引1:banana
索引2:orange
索引3:grape修改后的数组:fresh_apple fresh_banana fresh_orange fresh_grape

三、Bash 正则表达式:精准过滤文本数据

正则表达式(简称“正则”)是“描述字符串模式的规则”,核心用途是检索、过滤、替换符合规则的文本。在 Bash 中,常用 grep 命令结合正则处理日志、配置文件等文本数据。

3.1 常用工具:grep 与正则搭配

grep 是 Bash 中最常用的文本过滤工具,支持基础正则和扩展正则(需加 -E 参数),以下是高频选项:

选项功能说明
-E启用扩展正则(无需对 {}、+、? 等元字符转义)
-c统计匹配到的行数
-i忽略大小写(如匹配 Appleapple
-o只输出匹配到的内容(而非整行)
-v反向匹配(输出不包含匹配内容的行)
-n显示匹配行的行号
--color=auto高亮显示匹配到的内容(终端中更易识别)

3.2 核心元字符:构建正则规则

正则的核心是“元字符”——具有特殊含义的字符,掌握这些元字符就能组合出任意规则。以下是 Bash 中常用的元字符(分基础版和进阶版):

基础元字符(必掌握)
元字符含义示例
^匹配行首(开头位置)^root:匹配以 root 开头的行
$匹配行尾(结束位置)bash$:匹配以 bash 结尾的行
.匹配除换行符(\n)外的任意单个字符r..t:匹配 rootrest
[list]匹配“list”中的任意一个字符[abc]:匹配 abc
[^list]反向匹配(匹配“list”之外的任意一个字符)[^0-9]:匹配非数字字符
*匹配前面的子表达式“0次或多次”ro* t:匹配 rtrotroot
进阶元字符(扩展正则,需加 -E
元字符含义示例
{n}精确匹配“前面的子表达式”n次o{2}:匹配 oo(如 food 中的 oo
{n,}至少匹配“前面的子表达式”n次o{2,}:匹配 ooooo
{n,m}匹配“前面的子表达式”n到m次(n≤m)o{1,2}:匹配 ooo
+匹配“前面的子表达式”1次或多次(等价于 {1,}o+:匹配 ooo
?匹配“前面的子表达式”0次或1次(等价于 {0,1}o?:匹配空或 o

3.3 实战示例:用正则解决实际问题

以下示例基于 /etc/passwd 文件(Linux 系统用户配置文件),演示正则的实际用法。

示例5:匹配以 root 开头的行(行首匹配 ^
# 匹配以 root 开头的行,并显示行号
grep -n "^root" /etc/passwd

结果(类似):

1:root:x:0:0:root:/root:/bin/bash
示例6:匹配以 bash 结尾的行(行尾匹配 $
# 匹配以 bash 结尾的行,高亮显示
grep --color=auto "bash$" /etc/passwd

结果(类似):

root:x:0:0:root:/root:/bin/bash
user:x:1000:1000:user:/home/user:/bin/bash
示例7:匹配包含 3 个数字的行(用 [0-9]{3}
# 启用扩展正则(-E),匹配包含 3 个连续数字的行,统计行数(-c)
grep -Ec "[0-9]{3}" /etc/passwd

结果(类似):

5  # 表示有5行包含3个连续数字
示例8:反向匹配(排除以 # 开头的注释行)
# 查看 /etc/ssh/sshd_config,排除注释行(-v)和空行(^$)
grep -vE "^#|^$" /etc/ssh/sshd_config

结果:仅显示配置文件中的有效配置行(无注释、无空行)。

四、总结:三大特性的核心应用场景

特性核心价值典型应用场景
自定义函数代码复用、模块化封装重复逻辑(如日志打印、参数验证)、构建脚本框架
数组批量管理相关数据存储服务器列表、文件列表、配置参数,实现批量操作(如批量 ping 服务器)
正则表达式精准过滤、检索文本分析日志(如提取错误信息)、处理配置文件(如筛选有效配置)、验证输入格式

掌握这三大特性后,你可以写出更简洁、高效、易维护的 Bash 脚本。建议结合实际需求多练手(如写一个“批量检查服务器存活状态”的脚本,用数组存服务器IP,用函数封装 ping 逻辑,用正则过滤 ping 结果),逐步提升 Bash 实战能力。

http://www.xdnf.cn/news/1416097.html

相关文章:

  • Android原生HttpURLConnection上传图片方案
  • 打造智能写作工作流:n8n + 蓝耘MaaS平台完整实战指南
  • Apollo学习之决策模块
  • 【Linux手册】Unix/Linux 信号:原理、触发与响应机制实战
  • Ajax笔记(下)
  • 在.NET标准库中进行数据验证的方法
  • Java视觉跟踪入门:使用OpenCV实现实时对象追踪
  • 【开题答辩全过程】以 基于php的校园兼职求职网站为例,包含答辩的问题和答案
  • 【Android】使用Handler做多个线程之间的通信
  • 【Flask】测试平台开发,应用管理模块实现-第十一篇
  • 【lucene核心】impacts的由来
  • 旧物回收小程序:科技赋能,开启旧物新生之旅
  • 山东省信息技术应用创新开展进程(一)
  • 《C++进阶之STL》【红黑树】
  • OS+MySQL+(其他)八股小记
  • 【macOS】垃圾箱中文件无法清理的常规方法
  • 应用平台更新:可定制目录、基于Git的密钥管理与K8s项目自动化管理
  • Qt中的信号与槽机制的主要优点
  • LeetCode 142. 环形链表 II - 最优雅解法详解
  • 阿里云代理商:轻量应用服务是什么?怎么用轻量应用服务器搭建个人博客?
  • Linux性能调试工具之ftrace
  • JSP 输出语法全面解析
  • 制造业生产线连贯性动作识别系统开发
  • MCP SDK 学习二
  • 【开题答辩全过程】以 基于Java的网络购物平台设计与实现为例,包含答辩的问题和答案
  • 集合-单列集合(Collection)
  • Docker中使用Compose配置现有网络
  • Ubuntu 中复制粘贴快捷键
  • LeeCode 37. 解数独
  • 【嵌入式】【电机控制】基础知识列表