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

Shell编程之正则表达式与文本处理工具

一、正则表达式基础

1. 正则表达式概述

定义​:正则表达式(Regular Expression,简称Regex)是由普通字符​(如字母、数字、标点符号)与元字符​(具有特殊含义的专用字符)组成的字符串匹配规则,用于判断某字符串是否符合特定格式要求。

核心作用​:在Shell脚本中,通过文本处理工具(如grepsedawk)结合正则表达式,可以快速筛选、提取或修改目标文本内容,是自动化运维、日志分析、数据清洗等场景的基础技能。

类比理解​:正则表达式类似于“文本搜索的精准模板”——普通字符按字面意义匹配,元字符则定义了匹配的“规则模式”(如“任意字符”“重复次数”“开头/结尾位置”等)。


2. 正则表达式分类

根据POSIX(可移植操作系统接口)标准,正则表达式分为两大类,主要区别在于元字符的语法格式(是否需要转义)及支持的工具:

类型

支持工具

核心区别

典型使用场景

基本正则表达式(BRE,Basic Regular Expression)​

grep(默认)、sed(默认)、awk(部分支持)

元字符(如\{n\}\{n,\})需通过反斜杠``转义,语法相对严格。

简单文本过滤(如查找固定模式的行)。

扩展正则表达式(ERE,Extended Regular Expression)​

egrep(或grep -E)、awk(默认支持大部分ERE)、sed(配合-r选项)

元字符(如{n}{n,})无需转义,语法更简洁直观。

复杂模式匹配(如分组、逻辑“或”操作)。

关键区别示例​:

  • 匹配连续2个o

    • BRE(需转义):go\{2\}d(如grep "go\{2\}d" file

    • ERE(无需转义):go{2}d(如egrep "go{2}d" filegrep -E "go{2}d" file

工具默认行为​:

  • grep:默认使用BRE,若需使用ERE需加-E参数(或直接使用egrep)。

  • sed:默认使用BRE,若需使用ERE需加-r参数(部分新版本支持-E)。

  • awk:默认支持大部分ERE语法(如+?|无需转义)。


二、正则表达式核心元字符详解

1. 通用元字符(BRE与ERE均适用)

这些元字符在基本正则和扩展正则中功能一致,但部分在BRE中需要转义。

元字符

含义

用法示例

匹配示例

^

匹配字符串的开头位置

^a:匹配以字母a开头的行(如apple)。
^#:匹配以#开头的行(如注释行)。

^gd:匹配以gd开头的行。

$

匹配字符串的结尾位置

d$:匹配以字母d结尾的行(如god)。
^$:匹配空行(行首直接接行尾)。

word$:匹配以word结尾的行。

.

匹配除换行符

之外的任意单个字符

go.d:匹配go、任意1字符、d(如godgoXdgo1d)。

g..d:匹配g后跟任意2字符再跟d(如goodg9#d)。

*

匹配前一个字符的0次或多次重复

goo*d:匹配g后跟0个或多个o,最后是d(如gdgodgooood)。

go.*d:匹配g后跟任意字符(包括无)0次或多次,最后是d

``

转义字符,用于取消特殊字符的元字符含义(如让.匹配真正的点号)。

\.:匹配文本中的实际点号(如example.com中的.)。
\$:匹配文本中的$符号。

n\.:匹配n.(如n.1)。

注意​:在BRE(如默认grep/sed)中,元字符如{}+?|需通过\`转义才具有特殊含义;而在ERE(如egrep/grep -E/awk`)中,这些元字符通常无需转义。


2. 字符集合匹配(指定字符范围内的选择)

用于匹配一组字符中的任意一个,或排除某些字符。

元字符

含义

用法示例

匹配示例

[list]

匹配方括号内列出的任意一个字符​(字符列表)。

go[ola]d:匹配g+任意一个o/l/a+d(如godgol dgoa d)。
[a-z]:匹配任意小写字母。
[0-9]:匹配任意数字(0-9)。

[abc]:匹配abc
[A-Z0-9]:匹配任意大写字母或数字。

[^list]

匹配不在方括号内的任意一个字符(取反集合)。

[^0-9]:匹配非数字字符(如字母、符号)。
[^a-z]:匹配非小写字母。

[^A-Z]:匹配非大写字母的任意字符。

示例​:

  • [0-9]{3}:匹配连续3个数字(如123)。

  • [^ ]:匹配非空格的任意字符(如字母、符号)。


3. 次数匹配(控制前一个字符的重复次数)

用于精确控制某个字符或字符集合的重复次数范围。

元字符

含义

用法示例

匹配示例

\{n\}

匹配前一个字符恰好n次​(BRE需转义,ERE可直接用{n})。

go\{2\}d(BRE)或go{2}d(ERE):匹配g后跟2个o,最后是d(如gooood)。

a\{3\}(BRE):匹配aaa

\{n,\}

匹配前一个字符至少n次​(BRE需转义,ERE可直接用{n,})。

go\{2,\}d(BRE)或go{2,}d(ERE):匹配g后跟至少2个o,最后是d(如goodgooood)。

[0-9]\{3,\}:匹配至少3位数字。

\{n,m\}

匹配前一个字符n到m次​(BRE需转义,ERE可直接用{n,m})。

go\{2,3\}d(BRE)或go{2,3}d(ERE):匹配g后跟2-3个o,最后是d(如goodgooood)。

[a-z]\{2,4\}:匹配2-4个小写字母。

关键区别​:

  • 在BRE(如默认grep/sed)中,{}是普通字符,需转义为\{\}才能表示次数匹配。

  • 在ERE(如egrep/grep -E/awk)中,直接使用{n}{n,}等无需转义。

示例对比​:

  • BRE命令:grep "go\{2\}d" file(匹配gooood)。

  • ERE命令:egrep "go{2}d" filegrep -E "go{2}d" file(效果相同,无需转义)。


4. 扩展正则表达式特有元字符(仅ERE支持)

扩展正则表达式在BRE基础上增加了更灵活的操作符,简化了复杂模式的编写。

元字符

含义

用法示例

匹配示例

+

匹配前一个字符1次或多次​(至少1次,相当于\{1,\})。

go+d:匹配g后跟1个或多个o,最后是d(如godgoodgoood)。

a+:匹配1个或多个a(如aaa)。

?

匹配前一个字符0次或1次​(最多1次,相当于\{0,1\})。

go?d:匹配g后跟0个或1个o,最后是d(如gdgod)。

e?:匹配无e或有1个e

()

将括号内的内容视为一个整体​(用于分组操作,如重复、逻辑或)。

g(oo)+d:匹配g后跟1组或多组oo,最后是d(如good(1组oo)、gooood(2组oo))。

(ab)+:匹配ababab等。

`

`

逻辑“或”匹配(匹配多个模式中的任意一个,类似“或”关系)。

g(oo\|la)d:匹配g后跟oo(即good)或la(即glad)。

注意​:()|在BRE中无效(除非使用\(\)\|转义),仅在ERE中直接支持。


三、正则表达式核心元字符速查表

类别

元字符

功能

是否需要转义(BRE)​

ERE中是否转义

位置匹配

^

行首

$

行尾

单字符匹配

.

任意单个字符(除`

`)

``

转义特殊字符

是(需转义其他元字符)

是(按需转义)

字符集合

[list]

匹配列表中的任意一个字符

[^list]

匹配不在列表中的任意一个字符

次数匹配

*

前一个字符0次或多次

\{n\}

前一个字符恰好n次(BRE)

是(需加``)

否(直接{n}

\{n,\}

前一个字符至少n次(BRE)

是(需加``)

否(直接{n,}

\{n,m\}

前一个字符n到m次(BRE)

是(需加``)

否(直接{n,m}

{n}(ERE)

前一个字符恰好n次(ERE)

否(ERE无需转义)

扩展功能

+(ERE)

前一个字符1次或多次

否(仅ERE支持)

?(ERE)

前一个字符0次或1次

否(仅ERE支持)

()(ERE)

分组(整体操作)

否(仅ERE支持)

`

`(ERE)

逻辑“或”匹配

否(仅ERE支持)


四、正则表达式实战案例

案例1:电话号码匹配(BRE)

需求​:匹配区号025开头的电话号码,要求:

  • 号码与区号间分隔符为空格、-或无分隔

  • 号码本身必须是5或8开头,且为8位数字

正则表达式​:^(025)[ -]?[58][0-9]{7}$

分解说明​:

  • ^:匹配行首;

  • (025):匹配固定区号025(分组非必须,但提高可读性);

  • [ -]?:匹配分隔符(空格或-),?表示该分隔符出现0次或1次(即可以没有分隔符);

  • [58]:匹配号码首数字为58

  • [0-9]{7}:匹配后续7位数字(共8位);

  • $:匹配行尾。

测试数据(phone.txt)​​:

02588888888
025-5555555555
025 12345678
025 54321678
025ABC88888
025-85432109
028-85643210
0251-52765421

匹配命令​:

egrep "^(025)[ -]?[58][0-9]{7}$" phone.txt

预期输出​:

02588888888
025 54321678
025-85432109

案例2:电子邮箱匹配(ERE)

需求​:匹配符合标准格式的邮箱(用户名@子域名.二级域名.顶级域),要求:

  • 用户名:6-18位,以字母或下划线开头,允许字母、数字、部分符号(不含@和空格);

  • 子域名与二级域名:允许字母、数字、-_.

  • 顶级域:2-5位字母。

正则表达式​:^([a-zA-Z_][^@ ]{5,17})@[a-zA-Z0-9_\-.]+(\.[a-zA-Z0-9_\-.]+)?\.([a-zA-Z]{2,5})$

分解说明​:

  • ^:行首;

  • ([a-zA-Z_][^@ ]{5,17}):用户名部分:

    • [a-zA-Z_]:首字符为字母或下划线;

    • [^@ ]{5,17}:后续5-17位为非@、非空格的任意字符(总长度6-18位);

  • @:固定符号;

  • [a-zA-Z0-9_\-.]+:子域名/二级域名(允许字母、数字、_-.,至少1个字符);

  • (\.[a-zA-Z0-9_\-.]+)?:可选的二级域名(以.开头,后接合法字符,?表示0或1次);

  • \.([a-zA-Z]{2,5}):顶级域(以.开头,后接2-5位字母);

  • $:行尾。

测试数据(email.txt)​​:

zhangsan123@qq.com
li si@163.com
wang@wu@sina.com
zhao liu@126.com
qianqi@sina.com.cn

匹配命令​:

egrep "^([a-zA-Z_][^@ ]{5,17})@[a-zA-Z0-9_\-.]+(\.[a-zA-Z0-9_\-.]+)?\.([a-zA-Z]{2,5})$" email.txt

预期输出​:

zhangsan123@qq.com
qianqi@sina.com.cn

五、文本处理工具详解

1. sed流编辑器(Stream Editor)

(1)核心概念

sed是一种非交互式流编辑器,它逐行读取输入文本(文件或管道),根据预定义的规则(命令)对每行内容进行编辑(如删除、替换、插入),并将结果输出到屏幕或文件。​默认情况下,sed不会修改原文件​(除非使用-i选项)。

工作流程​:

  1. 读取​:从输入源(文件/标准输入)读取一行内容,存入模式空间(临时缓冲区);

  2. 执行​:在模式空间中按顺序执行所有sed命令(若指定行地址,则只对该行或行范围执行);

  3. 显示​:将处理后的模式空间内容输出到结果流(默认输出到屏幕),然后清空模式空间;

  4. 循环​:重复上述步骤,直到处理完所有输入行。

特点​:适合批量处理文本(如日志清洗、配置文件修改),尤其擅长基于行或模式的简单编辑操作。


(2)常用命令格式
sed [选项] '操作命令' 文件1 文件2...  
# 常用选项:
# -n:禁止默认输出(仅显示显式指定的内容,需配合p命令使用)
# -i:直接修改原文件(谨慎使用!建议先备份)
# -r 或 -E:支持扩展正则表达式(-r为旧版,-E为新版推荐)
# -e:指定多个操作命令(单命令时可省略)

(3)常用操作与示例

操作

功能

示例命令

详细说明

p

打印当前模式空间的内容

sed -n 'p' file(打印文件所有行)
sed -n '3p' file(打印第3行)

需配合-n选项避免重复输出默认内容。

d

删除当前行

sed '3d' file(删除第3行)
sed '/^$/d' file(删除所有空行)

直接移除匹配的行,不进入输出流。

s

替换字符

sed 's/old/new/' file(替换每行第一个oldnew
sed 's/old/new/g' file(替换所有old

g表示全局替换(一行内所有匹配项)。

a

在当前行后追加内容

sed '3a 新增内容' file(在第3行后插入一行新内容)

追加的文本会作为新行出现在指定行之后。

i

在当前行前插入内容

sed '3i 插入内容' file(在第3行前插入一行新内容)

插入的文本会作为新行出现在指定行之前。

=

打印当前行号

sed -n '=' file(打印文件每行的行号)

仅输出行号,不输出行内容。

n

读取下一行

sed -n 'n;p' file(打印奇数行:读取下一行并打印)

n命令会让sed跳过当前行的后续操作,直接处理下一行。


(4)寻址方式(指定操作的目标行)

sed支持通过行号正则表达式指定需要操作的行范围。

寻址方式

示例命令

说明

单行行号

sed -n '5p' file(打印第5行)

精确操作某一行。

最后一行

sed -n '$p' file(打印最后一行)

$表示文件的最后一行。

行范围

sed -n '1,3p' file(打印第1-3行)
sed -n '3,$p' file(打印第3行到末尾)

操作从起始行到结束行的所有行。

相对行范围

sed -n '1,+3p' file(打印第1行及其后3行,即1-4行)

从指定行开始,连续操作后续N行。

正则匹配行

sed -n '/关键词/p' file(打印包含“关键词”的行)

操作所有匹配正则表达式的行。

组合条件

sed -n '2,/nobody/p' file(打印第2行到第一个包含“nobody”的行)

从指定行开始,到匹配某个模式的行结束。


(5)高级操作示例
  • 删除空行​:

    sed '/^$/d' file.txt  # 删除所有空白行(行内容为空)
  • 注释特定行​(如给以root开头的行添加#注释):

    sed '/^root/ s/^/#/' /etc/passwd  # 将/etc/passwd中以root开头的行首添加#
  • 直接修改文件​(谨慎使用!):

    sed -i 's/old/new/g' file.txt  # 将文件中所有old替换为new,并直接保存到原文件
  • 复杂替换(保留匹配内容)​​:

    sed -n 's/\/bin\/bash/\/bin\/csh/p' /etc/passwd  # 将/bin/bash替换为/bin/csh,并打印修改的行
    # 使用\转义/,或改用其他分隔符(如|)避免冲突:
    sed -n 's|/bin/bash|/bin/csh|p' /etc/passwd

2. awk文本分析工具(Pattern-Scan Processing Language)

(1)核心概念

awk是一种面向字段的文本处理工具,它逐行读取输入文本,默认以空格或Tab键为分隔符将每行拆分为多个字段(1,2, ..., $NF),并通过模式(条件)+ 操作(命令)​的方式对符合条件的行进行灵活处理。awk更适合处理结构化数据(如日志、CSV文件),支持复杂的逻辑判断、数学运算和循环控制。

特点​:擅长按字段提取、统计和分析文本(如计算平均值、筛选特定条件的行、格式化输出)。


(2)基本语法
awk [选项] '模式或条件 {操作语句}' 文件1 文件2...  
# 常用选项:
# -F:指定字段分隔符(如-F: 表示以冒号为分隔符)

执行流程​:

  1. 逐行读取输入文本;

  2. 根据指定的分隔符(默认空格/TAB)将当前行拆分为多个字段(1,2,...NF,0表示整行);

  3. 若未指定模式,则对所有行执行操作;若指定了模式(如/关键词/NR>10),则仅对匹配模式的行执行操作;

  4. 在操作语句中,可通过内置变量(如$1、NF、NR)访问字段和行信息,并执行打印、计算等操作。


(3)常用内置变量

变量

含义

示例

$0

当前行的完整内容

awk '{print $0}' file(打印所有行)

$1~$n

当前行的第1~n个字段

awk -F: '{print $1}' /etc/passwd(打印每行第一个字段,如用户名)

NF

当前行的字段总数

awk '{print NF}' file(打印每行的字段数)

NR

当前处理的行号(从1开始)

awk '{print NR}' file(打印每行的行号)

FS

输入字段分隔符(同-F选项)

awk 'BEGIN{FS=":"} {print $1}' file

OFS

输出字段分隔符(默认空格)

`awk '{OFS="


(4)常用操作与示例

场景

命令示例

详细说明

打印所有内容

awk '{print}' fileawk '{print $0}' file

打印文件的每一行($0表示整行内容)。

打印指定行

awk 'NR==1 {print}' file(第1行)
awk 'NR==3 {print}' file(第3行)

通过行号(NR)精确控制要输出的行。

打印行范围

awk 'NR>=1 && NR<=3 {print}' file(1-3行)
awk '1,3 {print}' file

操作从第1行到第3行的所有内容。

打印奇数行/偶数行

奇数行:awk '(NR%2)==1 {print}' file
偶数行:awk '(NR%2)==0 {print}' file

通过取模运算(NR%2)判断行号的奇偶性。

按字段筛选

awk -F: '$3<5 {print $1,$3}' /etc/passwd(UID小于5的用户)

条件判断字段值(如第3字段UID),并输出指定字段。

统计匹配行数

awk '/\/bin\/bash$/{x++} END {print x}' /etc/passwd(统计bash用户数)

BEGIN块初始化变量,END块输出最终结果。

格式化输出

awk -F: '{print "用户名:" $1 ",UID:" $3}' /etc/passwd

自定义输出格式(结合字符串拼接)。

多分隔符支持

awk -F'[ ,:]' '{print $1}' file(以空格、逗号、冒号为分隔符)

方括号内指定多个分隔符(逻辑“或”关系)。


(5)高级功能
  • 调用Shell命令​:通过管道将字段传递给外部命令(如统计在线用户数):

    awk 'BEGIN{n=0; while("w" | getline) n++; print n-2}'  # 统计当前登录用户数(扣除标题和空行)
  • 数学运算​:计算某列的平均值(如第一列数字的平均值):

    awk '{sum+=$1; count++} END {print sum/count}' data.txt  # sum累加第一列,count统计行数
  • 数组统计​:统计每行首字段的出现次数并排序:

    awk '{a[$1]++} END {for(i in a) print a[i],i}' test.txt  # 统计每个首字段的出现次数
    awk '{a[$1]++} END {for(i in a) print a[i],i}' test.txt | sort -r  # 按次数降序排序
  • 条件判断与三元运算符​:

    awk -F: '{max=($3>$4)?$3:$4; print max}' /etc/passwd  # 取第3字段和第4字段的最大值
  • 内置函数​:如length($0)(计算行长度)、tolower($1)(转小写)、substr($1,2,3)(截取子串)。


六、总结对比

工具

核心定位

主要功能

正则表达式支持

典型使用场景

grep

快速文本搜索与过滤

根据模式匹配查找包含特定内容的行(支持过滤日志、查找关键字)

BRE(默认)、ERE(-E

日志分析、关键词查找、空行/注释过滤

sed

流式文本编辑

对文本行进行删除、替换、插入等操作(适合批量修改配置文件、清理日志)

BRE(默认)、ERE(-r/-E

配置文件修改、行内容替换、注释处理

awk

结构化文本分析与处理

按字段拆分文本,支持条件判断、数学运算、复杂逻辑(适合数据统计、报表生成)

ERE(默认支持高级正则)

日志统计、字段提取、数据格式化


文章转载自:

http://aKrGniKV.rzrbw.cn
http://obbsuVHK.rzrbw.cn
http://nQvUhZIK.rzrbw.cn
http://jgkLblMF.rzrbw.cn
http://KA5xLOXP.rzrbw.cn
http://D3YJ0CgB.rzrbw.cn
http://ZIyrLGhV.rzrbw.cn
http://FxmCxgTH.rzrbw.cn
http://CUP3UuY7.rzrbw.cn
http://mY5OzLy2.rzrbw.cn
http://G9JWRKiU.rzrbw.cn
http://jM2hbAC0.rzrbw.cn
http://nOYLL8Oc.rzrbw.cn
http://tDsJJ1UG.rzrbw.cn
http://EXGRZv7k.rzrbw.cn
http://BD3dYaJw.rzrbw.cn
http://yiGG7El8.rzrbw.cn
http://5X2CBS2n.rzrbw.cn
http://ExBlvQf6.rzrbw.cn
http://VI7ucT3g.rzrbw.cn
http://qipVcUUp.rzrbw.cn
http://r6vZGqKv.rzrbw.cn
http://eVkpuR7A.rzrbw.cn
http://DD5wsC59.rzrbw.cn
http://snljBtDZ.rzrbw.cn
http://3zPU7bOb.rzrbw.cn
http://A1xEMBDU.rzrbw.cn
http://1VEjx7DQ.rzrbw.cn
http://J0y71731.rzrbw.cn
http://Zi9e5B7D.rzrbw.cn
http://www.dtcms.com/a/377705.html

相关文章:

  • 软考系统架构设计师之UML统一建模语言
  • malloc概述
  • Nginx 实战系列(九)—— LVS负载均衡集群与DR模式部署指南
  • 利用美团龙猫用libxml2编写XML转CSV文件C程序
  • NJet支持使用json格式的配置文件了
  • 平时只会CRUD,没有高质量项目经验,我该怎么办
  • Vue项目创建方式(多种)
  • PMM:一款开源的数据库监控与管理工具
  • pyinstaller打包多个文件成一个exe
  • JavaScript逆向非对称加密算法
  • 基于EB_S32K3XX芯片的EMIOS_PWM的输出_1
  • 计算机毕设 java 高校会议信息管理系统的设计与实现 基于 SSM 框架的高校会议服务平台 Java+MySQL 的会议室预约与管理系统
  • Git 初识
  • 安全用电管理系统助力银行以全链路监测
  • 3.远程控制网络编程的设计上
  • 存算一体芯片生态评估:从三星PIM到知存科技WTM2101
  • 智联未来 点赋科技
  • SpringBoot项目健康检查端点返回为down排查思路
  • yolov8(yolov11)目标识别使用Tensorrt推理-2.0(C++Api)
  • 《Java中的IO流》
  • sql语句练习
  • 《深度学习的核心公式》
  • 划痕缺陷检测:3类成因,对应3套打光方案
  • 摆动序列:如何让数组“上下起伏”地最长?
  • 模型 公地悲剧
  • 深入理解 Android targetSdkVersion:从 Google Play 政策到依赖冲突
  • DDNS动态域名解析服务:原理与工具详解全攻略,外网畅访内网设备用自定义固定域名
  • 【系统分析师】第20章-关键技术:信息物理系统分析与设计(核心总结)
  • 批量更新数据:Mybatis update foreach 和 update case when 写法及比较
  • 九、瑞萨发布RZT/N认证的PROFINET-IRT和PROFIdrive软件协议栈