目录
前言
在计算机技术飞速发展的今天,数据处理和系统管理变得日益复杂,而文本作为信息的重要载体,在其中扮演着关键角色。Shell 编程、正则表达式以及文本处理器作为处理文本和实现自动化任务的核心技术,成为了每一位系统管理员、开发人员和数据处理人员不可或缺的技能。它们如同精准的手术刀,能够在海量的文本数据中快速定位、提取和转换信息,让繁琐的重复性工作变得高效而有序。
Shell 编程是与操作系统交互的桥梁,它允许用户通过编写脚本来自动化执行一系列命令,实现系统管理、文件操作、进程控制等任务。从简单的批量文件重命名,到复杂的系统监控和部署流程,Shell 脚本都能发挥重要作用。掌握 Shell 编程,意味着能够将日常的手动操作转化为可重复执行的脚本,大大提高工作效率,减少人为错误。
正则表达式则是文本模式匹配的强大工具,它定义了一种字符串匹配的模式,能够快速筛选、提取和替换符合特定模式的文本内容。无论是在日志分析中提取关键信息,还是在数据清洗中去除无效数据,正则表达式都能凭借其简洁而强大的语法,轻松应对各种复杂的文本处理需求。它就像是一把万能钥匙,能够打开文本处理的各种复杂场景。
文本处理器,如 sed、awk 等,是专门用于文本处理的实用工具,它们与 Shell 编程和正则表达式紧密结合,形成了一套完整的文本处理体系。sed 擅长对文本进行流式编辑,能够快速实现文本的替换、删除、插入等操作;awk 则是一种强大的文本分析工具,能够对文本进行格式化处理、统计分析等。这些工具的灵活运用,使得我们能够在不编写复杂程序的情况下,完成各种高效的文本处理任务。
一:正则表达式
正则表达式(Regular Expression,RE),下面先了解正则表达式的定义及用途。
1:正则表达式的定义
正则表达式又称正规表达式、常规表达式,在代码中常简写为 regex、regexp 或 RE。它是用单个字符串描述、匹配一系列符合某个句法规则的字符串,简单来说,是一种匹配字符串的方法,可通过特殊符号实现快速查找、删除、替换特定字符串。
正则表达式常用于脚本编程与文本编辑器,许多文本处理器和程序设计语言都支持它,如 Linux 系统常见的文本处理器(grep、egrep、sed、awk)以及应用广泛的 Python 语言。它具有强大的文本匹配功能,能高效处理大量文件
2.正则表达式用途:
对于普通计算机用户,使用正则表达式的机会较少,难以体会其优势,但对于系统管理员而言,正则表达式是必备技能。系统运行会产生大量信息,其中部分至关重要,部分仅为提示信息。管理员可快速查找位置。
二、基础正则表达式
在 Linux 系统的文件处理工具中,grep 与 sed 支持基础正则表达式,egrep 与 awk 支持扩展正则表达式。
1.基础正则表达式
提前准备名为 test.txt 的测试文件
1.1查找特定字符
执行以下命令可从 test.txt 文件中查找特定字符 “the” 所在位置。“-n” 表示显示行号,“-i” 表示不区分大小写,命令执行后,符合匹配标准的字符会以红色显示(本文中加粗显示代替)。
[root@localhost ~]# grep -n 'the' test.txt
4:the tongue is boneless but it breaks bones.12!
5:google is the best tools for search keyword.
#增加-i选项忽略大小写
[root@localhost ~]# grep -in 'the' test.txt
3:The home of Football on BBC Sport online.
4:the tongue is boneless but it breaks bones.12!
5:google is the best tools for search keyword.
若反向选择,查找不包含 “the” 字符的行,可通过 grep 命令的 “-v” 选项实现,并配合 “-n” 一起使用显示行号。
[root@localhost ~]# grep -vn 'the' test.txt
1:he was short and fat.
2:he was weating a blue polo shirt with black pants.
3:The home of Football on BBC Sport online.
6:PI=3.14
7:a wood cross!
8:Actions speak louder than words
9:
10:#woood #
11:#woooooooood #
12:AxyzxyzxyzxyzC
13:I bet this place is really spooky late at night!
14:Misfortunes never come alone/single.
15:I shouldn't have lett so tast.
16:
1.2利用中括号 “[]” 来查找集合字符
查找 “shirt” 与 “short” 这两个字符串时,可执行以下命令,“[]” 中无论有几个字符,都仅代表一个字符,“[io]” 表示匹配 “i” 或者 “o”。
[root@localhost ~]# grep -n 'sh[io]rt' test.txt
1:he was short and fat.
2:he was weating a blue polo shirt with black pants.
查找包含重复单个字符 “oo” 时,执行以下命令:
[root@localhost ~]# grep -n 'oo' test.txt
3:The home of Football on BBC Sport online.
5:google is the best tools for search keyword.
7:a wood cross!
10:#woood #
11:#woooooooood #
13:I bet this place is really spooky late at night!
查找 “oo” 前面不是 “w” 的字符串,可通过集合字符的反向选择 “[^]” 实现,如执行 “grep -n ' w oo' test.txt” 命令。
[
root@localhost ~]# grep -n '[^w]oo' test.txt
3:The home of Football on BBC Sport online.
5:google is the best tools for search keyword.
10:#woood #
11:#woooooooood #
13:I bet this place is really spooky late at night!
1.3查找行首"^"与行尾字符"$"
若要查询以 “the” 字符串为行首的行,可通过 “^” 元字符实现
[root@localhost ~]# grep -n '^the' test.txt
4:the tongue is boneless but it breaks bones.12!
查询以小写字母开头的行可通过 “^[a - z]” 规则过滤,查询大写字母开头的行使用 “^[A - Z]” 规则,查询不以字母开头的行使用 “[a - z A - Z]” 规则。
[root@localhost ~]# grep -n '^[a-z]' test.txt
1:he was short and fat.
2:he was weating a blue polo shirt with black pants.
4:the tongue is boneless but it breaks bones.12!
5:google is the best tools for search keyword.
7:a wood cross!
^” 符号在元字符集合 “[]” 内外作用不同,在 “[]” 内表示反向选择,在 “[]” 外代表定位行首。若想查找以某一特定字符结尾的行,可使用 “$” 定位符。例如,查询以小数点(.)结尾的行,因小数点在正则表达式中是元字符,需用转义字符 “\” 将其转化为普通字符。
[root@localhost ~]# grep -n '\.$' test.txt
1:he was short and fat.
2:he was weating a blue polo shirt with black pants.
3:The home of Football on BBC Sport online.
5:google is the best tools for search keyword.
14:Misfortunes never come alone/single.
15:I shouldn't have lett so tast.
查询空白行时,执行 “grep -n '^$' test.txt” 命令即可。
[root@localhost ~]# grep -n '^$' test.txt
9:
16:
1.4查找任意一个字符 “.” 与重复字符 “*”
在正则表达式中,小数点(.)是元字符,代表任意一个字符。例如执行以下命令可查找 “w??d” 的字符串,即四个字符,以 w 开头 d 结尾。
[root@localhost ~]# grep -n 'w..d' test.txt
5:google is the best tools for search keyword.
7:a wood cross!
8:Actions speak louder than words
""代表重复零个或多个前面的单字符,“o*” 表示拥有零个(即空字符)或大于等于一个 “o” 的字符,因允许空字符,执行 “grep -n 'o' test.txt” 命令会输出文本中所有内容。若为 “oo”,则第一个 “o” 必须存在,第二个 “o” 是零个或多个 “o”,所以包含 “o、oo、ooo” 等的资料都符合标准。同理,查询包含至少两个 “o” 以上的字符串,执行 “grep -n 'oo' test.txt” 命令即可。
[root@localhost ~]# grep -in 'woo*d' test.txt
7:a wood cross!
10:#woood #
11:#woooooooood #
执行以下命令可查询以 w 开头 d 结尾,中间字符可有可无的字符串。
[root@localhost ~]# grep -in 'w.*d' test.txt
1:he was short and fat.
5:google is the best tools for search keyword.
7:a wood cross!
8:Actions speak louder than words
10:#woood #
11:#woooooooood #
执行以下命令可查询任意数字所在行。
[root@localhost ~]# grep -n '[0-9][0-9]*' test.txt
4:the tongue is boneless but it breaks bones.12!
6:PI=3.14
1.5查找连续字符范围 “{}”
在 Shell 中有特殊意义,使用时需利用转义字符 “\” 将其转换为普通字符,“{}” 字符的使用方法如下: 查询两个 “o” 的字符:
[root@localhost ~]# grep -n 'o\{2\}' test.txt
3:The home of Football on BBC Sport online.
5:google is the best tools for search keyword.
7:a wood cross!
10:#woood #
11:#woooooooood #
13:I bet this place is really spooky late at night!
查询以 w 开头以 d 结尾,中间包含 2 - 5 个 “o” 的字符串:
[root@localhost ~]# grep -n 'wo\{2,5\}d' test.txt
7:a wood cross!
10:#woood #
查询以 w 开头以 d 结尾,中间包含 2 个或 2 个以上 “o” 的字符串:
[root@localhost ~]# grep -n 'wo\{2,\}d' test.txt
7:a wood cross!
10:#woood #
11:#woooooooood
#
2.元字符总结
元字符 | 说明 |
---|---|
将下一个字符标记为特殊字符、原义字符、向后引用或八进制转义 | |
^ | 匹配输入字符串的开始位置 |
$ | 匹配输入字符串的结束位置 |
* | 匹配前面的子表达式零次或多次 |
+ | 匹配前面的子表达式一次或多次 |
? | 匹配前面的子表达式零次或一次 |
. | 匹配除换行符(\n、\r)之外的任何单个字符 |
[a - z] | 字符范围,匹配指定范围内的任意字符 |
{n} | n 是非负整数,匹配确定的 n 次 |
{n,} | n 是非负整数,至少匹配 n 次 |
{n,m} | m 和 n 均为非负整数,n <= m,最少匹配 n 次且最多匹配 m 次 |
\d | 匹配一个数字字符,等价于 [0 - 9] |
\D | 匹配一个非数字字符,等价于 0 - 9 |
\s | 匹配任何空白字符,包括空格、制表符、换页符等,等价于 [\n\r\t\f\v] |
\S | 匹配任何非空白字符,等价于 \n\r\t\f\v |
\w | 匹配字母、数字、下划线,等价于 '[A - Za - z0 - 9_]' |
\W | 匹配非字母、数字、下划线,等价于 'A - Za - z0 - 9_' |
\n | 匹配一个换行符 |
\f | 匹配一个换页符 |
\r | 匹配一个回车符 |
3.扩展正则表达式
若要使用扩展正则表达式,需用 egrep 或 awk 命令。awk 命令将在后续小节讲解,此处先使用 egrep 命令。egrep 命令与 grep 命令用法相似,是用于搜索文件获取模式的工具,可搜索文件中的任意字符串和符号,也能搜索一个或多个文件中的字符串,搜索提示符可以是单个字符、字符串、单词或句子。
与基础正则表达式类似,扩展正则表达式也包含多个元字符,常见的扩展正则表达式元字符及其作用和示例如下表所示:
元字符 | 作用与示例 |
---|---|
+ | 作用:重复一个或一个以上的前一个字符。示例:执行 “egrep -n 'wo+d' test.txt” 命令,可查询 “wood”“woood”“woooooood” 等字符串 |
? | 作用:匹配零个或一个的前一个字符。示例:执行 “egrep -n 'bes?t' test.txt” 命令,可查询 “bet”“best” 这两个字符串 |
作用:使用 “或者(or)” 的方式找出多个字符。示例:执行 “egrep -n 'of | |
() | 作用:查找 “组” 字符串。示例:“egrep -n 't (al) st' test.txt”,因 “task” 与 “test” 中 “t” 与 “st” 重复,将 “a” 与 “e” 列于 “()” 符号中并用 “ |
()+ | 作用:辨别多个重复的组。示例:“egrep -n 'A (xyz)+C' test.txt”,该命令用于查询开头为 “A”、结尾为 “C”,中间有一个以上 “xyz” 字符串的内容 |
三:文本处理器
在Linux系统中包含很多种类的文本处理或文本编辑器,其中常用的是gerp,sed,awk更是shell编程中经常用到的文本处理工具,称为shell编程三剑客。
1.sed工具
sed(Stream EDitor)是强大且简单的文本解析转换工具,能读取文本,并依据指定条件对文本内容进行编辑(删除、替换、添加、移动等),最后输出所有行或仅输出处理后的某些行。sed 可在无交互的情况下完成复杂文本处理操作,广泛应用于 Shell 脚本,用于实现各种自动化处理任务。
sed 的工作流程包含读取、执行和显示三个过程:
读取:sed 从输入流(文件、管道、标准输入)中读取一行内容,并存储到临时缓冲区(即模式空间,pattern space)。
执行:默认情况下,所有 sed 命令在模式空间中顺序执行,除非指定行地址,否则 sed 命令会在所有行上依次执行。
显示:将修改后的内容发送到输出流,发送数据后,模式空间会被清空。
sed 的命令格式为: sed [选项] "操作" 参数 sed [选项] -f scriptfile 参数
常见的 sed 命令选项如下:
-e 或 --expression=:用指定命令或脚本来处理输入的文本文件。
-f 或 --file=:用指定的脚本文件来处理输入的文本文件。
-h 或 --help:显示帮助信息。
-n、--quiet 或 --silent:仅显示处理后的结果。
-i:直接编辑文本文件。
“操作” 用于指定对文件的操作行为,即 sed 命令。通常采用 “[n1 [,n2]] 操作参数” 的格式,n1、n2 可选,代表进行操作的行数,如操作在 5 - 20 行之间进行,可表示为 “5,20 动作行为” 。常见操作如下:
a:增加,在当前行下面增加一行指定内容。
c:替换,将选定行替换为指定内容。
d:删除,删除选定的行。
i:插入,在选定行上面插入一行指定内容。
p:打印,若指定行,则打印指定行;若不指定行,则打印所有内容;若有非打印字符,以 ASCII 码输出,通常与 “-n” 选项一起使用。
s:替换,替换指定字符。
y:字符转换。
实例:
1.1输出符合条件的文本(p 表示正常输出):
[root@localhost ~]# sed -n 'p' test.txt
he was short and fat.
he was weating a blue polo shirt with black pants.
The home of Football on BBC Sport online.
the tongue is boneless but it breaks bones.12!
//省略内容4
#输出第三行
[root@localhost ~]# sed -n '3p' test.txt
The home of Football on BBC Sport online.
#输出第三行到第五行
[root@localhost ~]# sed -n '3,5p' test.txt
The home of Football on BBC Sport online.
the tongue is boneless but it breaks bones.12!
google is the best tools for search keyword.
#输出所有奇数行,n表示进入下一行
[root@localhost ~]# sed -n 'p;n' test.txt
he was short and fat.
#输出1到5行之间的奇数行
[root@localhost ~]# sed -n '1,5{p;n}' test.txt
he was short and fat.
The home of Football on BBC Sport online.
google is the best tools for search keyword.
在执行 “sed -n '10,$[n;p}' test.txt” 命令时,读取的第 1 行是文件的第 10 行,第 2 行是第 11 行,依此类推,所以输出的偶数行是文件的第 11 行、13 行直至文件结尾,包括空行。
[root@localhost~]#sed -n '/the/p' test.txt
//输出包含the的行
the tongue is boneless but it breaks bones.12!
google is the best tools for search keyword.The year ahead will test our political
establishment to the limit.
[root@localhost~]#sed -n '4,/the/p' test.txt
//输出从第4行至第一个包含the的行
the tongue is boneless but it breaks bones.12!
google is the best tools for search keyword.
[root@localhost~]#sed -n '/the/=' test.txt
//输出包含the的行所在的行号,等号(=)用来输出行号
4
5
6
[root@localhost ~]#sed -n '/^PI/p' test.txt
//输出以PI开头的行
PI=3.141592653589793238462643383249901429
[root@localhost~]#sed -n '/[0-9]$/p' test.txt
//输出以数字结尾的行
PI=3.141592653589793238462643383249901429
[root@localhost~]#sed -n'/\<wood\>/p' test.txt
//输出包含单词wood的行,<、\>代表单词边界
a wood cross!
1.2删除文本中的内容(d)
以下示例展示了 sed 命令的常用删除用法,使用 nl 命令计算文件行数,可更直观查看命令执行结果。
[root@localhost~]#nl test.txt|sed '3d'
//删除第3行
1 he was short and fat.2He was wearing a blue polo shirt with black pants.4the
tongue is boneless but it breaks bones.12!
5 google is the best tools for search keyword.6 The year ahead will test our political
establishment to the limit.……
[root@localhost~]#nl test.txt| sed '3,5d'
//删除第3 - 5行
1 he was short and fat.2 He was wearing a blue polo shirt with black pants.6 The
yearahead will test our political establishment to the limit. 7
PI=3.141592653589793238462643383249901429
8a wood cross!……
1.3替换符合条件的文本
使用 sed 命令进行替换操作时,会用到 s(字符串替换)、c(整行 / 整块替换)、y(字符转换)等命令选项,常见用法如下:
ed's/the/THE/' test.txt
//将每行中的第一个the替换为THE
sed's/1/L/2' test.txt
//将每行中的第2个1替换为L
sed's/the/THE/g' test.txt //将文件中的所有the替换为THE
sed's/o//g' test.txt //将文件中的所有o删除(替换为空串)
sed's/^/#/'test.txt
//在每行行首插入#号
sed'/the/s/^/#/'test.txt
//在包含the的每行行首插入#号
sed's/$/EOF/'test.txt
//在每行行尾插入字符串EOF
sed 3,5s/the/THE/g' test.txt
//将第3 - 5行中的所有the替换为THE
sed'/the/s/o/0/g' test.txt
//将包含the的所有行中的o都替换为0
1.4迁移符合条件的文本
使用 sed 命令迁移符合条件的文本时,常用到以下参数:
H:复制到剪贴板。
g、G:将剪贴板中的数据覆盖 / 追加至指定行。
w:保存为文件。
r:读取指定文件。
a:追加指定内容。
sed '/the/{H;d};$G' test.txt
//将包含the的行迁移至文件末尾,{;}用于多个操作
sed '1,5{H;d};17G' test.txt
//将第1 - 5行内容转移至第17行后
sed '/the/w out.file' test.txt
//将包含the的行另存为文件out.file
sed '/the/r /etc/hostname' test.txt
//将文件/etc/hostname的内容添加到包含the的每行以后
sed '3aNew' test.txt
//在第3行后插入一个新行,内容为New
sed /the/aNew' test.txt
//在包含the的每行后插入一个新行,内容为New
sed '3aNew1\nNew2' test.txt
//在第3行后插入多行内容,中间的\n表示换行
2.awk工具
在 Linux/UNIX 系统里,awk 是功能强大的编辑工具。它逐行读取输入文本,依据指定的匹配模式查找内容,对符合条件的部分进行格式化输出或过滤处理。即便没有交互操作,awk 也能完成复杂的文本处理任务,在 Shell 脚本中广泛应用,助力实现各种自动化配置工作。
通常,awk 的命令格式如下:
awk选项 '模式或条件{编辑指令}' 文件1 文件2...
:用于过滤并输出文件中符合条件的内容。awk -f脚本文件 文件1 文件2...
:从脚本中调用编辑指令,实现对文件内容的过滤和输出。
示例,通过awk 命令对/etc/passwd
文件的处理过程如下:
[root@localhost ~]# awk -F: '{print $1,$2,$3}' /etc/passwd
root x 0
bin x 1
daemon x 2
adm x 3
lp x 4
sync x 5
shutdown x 6
halt x 7
mail x 8
operator x 11
games x 12
ftp x 14
nobody x 65534
systemd-coredump x 999
dbus x 81
polkitd x 998
saslauth x 997
dhcpd x 177
sshd x 74
tss x 59
unbound x 996
chrony x 995
awk 包含几个特殊的内建变量,可直接使用:
FS
:指定每行文本的字段分隔符,默认为空格或制表位。NF
:当前处理行的字段个数。NR
:当前处理行的行号(序数)。$0
:当前处理行的整行内容。$n
:当前处理行的第 n 个字段(第 n 列)。FILENAME
:被处理的文件名。RS
:数据记录分隔符,默认为\n
,即每一行作为一条记录。
用法实例:
按行输出文本
awk '{print}' test.txt //输出所有内容,等同于cat test.txt
awk '{print $0}' test.txt //输出所有内容,等同于cat test.txt
awk 'NR==1,NR==3{print}' test.txt
//输出第1 - 3行内容
awk '(NR>=1)&&(NR<=3){print}' test.txt
//输出第1 - 3行内容
awk 'NR==1||NR==3{print}' test.txt
//输出第1行、第3行内容
awk '(NR%2)==1{print}' test.txt
//输出所有奇数行的内容
awk '(NR%2)==0{print}' test.txt
//输出所有偶数行的内容
awk '/root/{print}' /etc/passwd //输出以root开头的行
awk '/nologin$/{print}' /etc/passwd //输出以nologin结尾的行
awk "BEGIN{x=0}; /\/bin\/bash$/{x++}; END {print x}" /etc/passwd
//统计以/bin/bash结尾的行数,等同于grep -c "/bin/bash$" /etc/passwd
awk "BEGIN{RS=\"\"}; END {print NR}" /etc/squid/squid.conf
//统计以空行分隔的文本段落数
按字段输出文本
awk '{print $3}' test.txt
//输出每行中(以空格或制表位分隔)的第3个字段
awk '{print $1,$3}' test.txt
//输出每行中的第1、3个字段
awk -F":" '$2==""{print}' /etc/shadow
//输出密码为空的用户的shadow记录
awk "BEGIN{FS=\":\"}; $2==\"\"{print}" /etc/shadow
//输出密码为空的用户的shadow记录
awk -F":" '$7~"/bash"{print $1}' /etc/passwd
//输出以冒号分隔且第7个字段中包含/bash的行的第1个字段
awk "($1~\"nfs\")&&(NF==8){print $1,$2}" /etc/services //输出包含8个字段且第1个字段中包含nfs的行的第1、2个字段
awk -F":" "($7!=\"/bin/bash\")&&($7!=\"/sbin/nologin\"){print}" /etc/passwd //输出第7个字段既不为/bin/bash也不为/sbin/nologin的所有行
总结
文档围绕 Shell 编程中的正则表达式与文本处理器展开,介绍了正则表达式的定义、用途、基础及扩展用法,以及 sed 和 awk 等文本处理器的工作原理、命令选项和使用示例,表明这些知识在 Shell 编程、系统管理、数据处理等领域至关重要 。