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

一、正则表达式

1.1 正则表达式概述

1. 正则表达式的定义

正则表达式又称正规表达式、常规表达式。在代码中常简写为 regex 、 regexp 或 RE 。
正则表达式是使用单个字符串来描述、匹配一系列符合某个句法规则的字符串,简单来说,
是一种匹配字符串的方法,通过一些特殊符号,实现快速查找、删除、替换某个特定字符串。

2. 正则表达式用途

正则表达式对于系统管理员来说是非常重要的,系统运行过程中会产生大量的信息,这些信息有些是非常重要的,有些则仅是普通信息,这时可以通过正则表达式快速提取"有问题"的信息。目前很多软件也支持正则表达式,最常见的就是邮件服务器。在Internet中,垃圾/广告邮件经常会造成网络拥塞,如果在服务器端就将这些问题邮件剔除的话,就可以减少不必要的宽带消耗。

1.2 基础正则表达式

在linux中常见的文件处理工具中grep和sed支持基础正则表达式。要掌握基础正则表达式,首先必须了解正则表达式所包含元字符的意义,下面通过grep命令以举例的方式逐个介绍。

1. 基础正则表达式示例

(1) 查找特定字符

查找特定字符非常简单,使用格式为:

grep 选项 '查找关键字' 要查找的文件或数据流

(2) 利用中括号"\[\]"来查找集合字符

可以通过中括号更精细地查找要查找的字符,例如:

#查找字符串,开头为sh和结尾rt,但中间位置的字符不同

grep 'shiort' 要查找的文件或数据流

意思是查找以前面为sh,后面为rt,但是中间位置为"i"或者"o"的字符串

#也可以反向搜索,查找中间位置不是"i"或者"o"的字符串

grep 'sh\^iort' 要查找的文件或数据流

也可以用在开头位置或结尾位置,过滤开头是"i"或者"o"的字符串。

grep '\^ioshrt' 要查找的文件或数据流

grep 'shrt\^io' 要查找的文件或数据流

#要范围性地查找或过滤字符串

grep 'sha-zrt' 要查找的文件或数据流

意思是中间位置的字符是a到z且开头为sh,后面为rt的都在查找的范围内。

注意a-z可以换为0-9或A-Z,要指定多个范围可以写在前一个范围的后面,不需要空格。

(3) 查找任意一个字符"."与重复字符"*"

在正则表达式中,小数点也是一个元字符,代表任意一个字符。例如,执行以下命令就可以查找"w??d"的字符串,即共有4个字符,以w开头,以d结尾

grep -n 'w..d' 要查找的文件或数据流 #注意小数点只会匹配一个任意字符。

#命令执行之后会从文件或数据流中找到以w开头,以d结尾,中间是任意两个字符的字符串。

在正则表达式中,"*"可以匹配前面一个字符0次或多次,所以通过将w..d中的后一个小数点换为一个*,就可以匹配开头为w,结尾为d的,中间有任意字符、任意数量的字符串(这是"."和"*"结合使用得到的结果)。注意,在这里"*"只是对自己前面的一个字符"."进行匹配0次或多次。再举一个例子就是:

grep 'ooo*' 要查找的文件或数据流

#这个只会匹配"*"前面一个o0次或多次,开头的另外两个o不会进行匹配。

(4) 查找连续字符范围"{}"

在上面的示例中,使用了"."与"*"来设定零个到无限多个重复的字符,如果想要限制一个 范围内的重复的字符串该如何实现呢?例如,查找三到五个o的连续字符,这个时候就需要使用基础正则表达式中的限定范围的字符"{}"。因为"{}"在Shell中具有特殊意义,所以在使用"{}"字符时,需要利用转义字符"\",将"{}"转换为普通字符。"{}"字符的使用方法如下:

#查询两个o的字符
grep 'o\{2\}' 要查找的文件或数据流

#查询以 w 开头以 d 结尾,中间包含 2~5 个 o 的字符串。

grep 'wo\{2,5\}d' 要查找的文件或数据流

#查询以 w 开头以 d 结尾,中间包含 2 个或 2 个以上 o 的字符串

grep 'wo\{2,\}d' 要查找的文件或数据流

2. 元字符总结

常见的基础正则表达式的元字符主要包括以下几个:

|-----------|-------------------------------------------------------------------------------------------------------------------------------------|
| ^ | 匹配输入字符串的开始位置。除非在方括号表达式中使用,表示不包含该字符集合。要匹配 "^"字符本身,请使用"\^"。 |
| | 匹配输入字符串的结尾位置。如果设置了 RegExp 对象的 Multiline 属性,则 "" 也匹配 '\n' 或 '\r' 。 要匹配"" 字符本身,请使用 "\\"。 |
| . | 匹配除 "\r、\n" 之外的任何单个字符。 |
| \ | 反斜杠,又叫转义字符,去除其后紧跟的元字符或通配符的特殊意义。 |
| * | 匹配前面的子表达式零次或多次。要匹配 "*" 字符,请使用 "\*"。 |
| \[\] | 字符集合。匹配所包含的任意一个字符。例如, "abc" 可以匹配 "plain" 中的 "a"。 |
| \^ | 赋值字符集合。匹配未包含的一个任意字符。例如, "\^abc" 可以匹配 "plain" 中任何一个字母。 |
| n1-n2 | 字符范围。匹配指定范围内的任意一个字符。例如, "a-z" 可以匹配 "a" 到 "z" 范围内的任意一个小写字母字符。 注意:只有连字符( - )在字符组内部,并且出现在两个字符之间时,才能表示字符的范围;如果出现在字符组的开头,则只能表示连字符本身。 |
| {n} | n 是一个非负整数,匹配确定的 n 次。例如, "o{2}" 不能匹配 "Bob" 中的 "o" ,但是能匹配 "food" 中的"oo" |
| {n,} | n 是一个非负整数,至少匹配 n 次。例如, "o{2,}" 不能匹配 "Bob" 中的 "o" ,但能匹配 "foooood" 中的所有 o 。 "o{1,}" 等价于 "o+" 。 "o{0,}" 则等价于 "o*" |
| {n,m} | m 和 n 均为非负整数,其中 n<=m ,最少匹配 n 次且最多匹配 m 次 |

1.3 扩展正则表达式

扩展正则表达通过使用范围更广的扩展正则表达式能够简化使用正则表达式的指令。例如查询除文件中空白行与行首为"#"之外的行(通常用于查看生效的配置文件):

grep -v '^$' 要查找的文件或数据流 | grep -v '^#'

#使用扩展正则表达式之后

egrep -v '^$ | ^#' 要查找的文件或数据流

#单引号内的管道符号表示或者

若要使用扩展正则表达式,需要使用egrep或awk命令。egrep 命令是一个搜索文件获得模式,使用该命令可以搜索文件中的任意字符串和符号,也可以搜索一个或多个文件的字符串,一个提示符可以是单个字符、一个字符串、一个字或一个句子。在扩展正则表达式中,常见的扩展正则表达式的元字符主要包括以下几个:

|-----|----------------------------------------------------------------------------------------------------------------------------------------------------------------|
| + | 作用:重复匹配一个或者一个以上的前一个字符 示例:执行 "egrep -n 'wo+d' test.txt" 命令,即可查询 "wood" "woood" "woooooood" 等字符串 |
| ? | 作用:匹配零个或者一个的前一个字符 示例:执行 "egrep -n 'bes?t' test.txt" 命令,即可查询 "bet""best" 这两个字符串 |
| | | 作用:使用或者( or) 的方式找出多个字符 示例:执行 "egrep -n 'of|is|on' test.txt" 命令即可查询 "of" 或者 "if" 或者 "on" 字符串 |
| () | 作用:查找 " 组 " 字符串 示例: "egrep -n 't(a|e)st' test.txt" 。 "tast" 与 "test" 因为这两个单词的 "t" 与 "st" 是重复的,所以将 "a" 与 "e" 列于"()" 符号当中,并以 "|" 分隔,即可查询 "tast" 或者 "test" 字符串。 |
| ()+ | 作用:辨别多个重复的组 示例: "egrep -n 'A(xyz)+C' test.txt" 。该命令是查询开头的 "A" 结尾是 "C" ,中间有一个以上的 "xyz" 字符串的意思。 |

二、文本处理器

在Linux和Unix系统中包含很多种类的文本处理器或文本编辑器,而grep、sed、awk更是Shell编程中经常使用到的文本处理工具。

2.1 sed工具

sed(Stream EDitor)是一个流编辑器,可以读取文本,并根据指定的条件对文本内容进行编辑(删除、替换、添加、移动等),最后输出所有行或经过处理的行。sed也可以在无交互的情况下实现相当复杂的文本处理操作,被广泛应用于脚本中,完成自动化任务。

sed的主要工作流程包括读取、执行和显示三个过程:

  • 读取:sed从输入流中读取一行内容并存储到临时的缓冲区中(又称模式空间)。
  • 执行:默认情况下,所有的sed命令都在模式空间中顺利地执行,除非指定了行的地址,否则sed命令将会在所有的行上依次执行。
  • 显示:发送修改后的内容到输出流。在发送数据后,模式空间将会被清空。

注意:默认情况下所有的 sed 命令都是在模式空间内执行的,因此输入的文件并不会发生任何变化,除非是用重定向存储输出。

1. sed命令的常见用法

通常情况下调用sed命令有两种模式,如下所示:

sed 选项 '操作' 参数

sed 选项 -f scriptfile 参数

参数是指操作的目标文件,多个文件之间用","进行分割。"-f"是指定脚本文件,对参数使用指定的脚本文件中的命令进行处理。常见的sed命令选项主要包含以下几种:

|-------------------|-----------------------|
| -e或--expression= | 表示用指定命令或者脚本处理输入的文本文件。 |
| -f或--file= | 表示用指定的脚本文件来处理输入的文本内容。 |
| -h或--help | 显示帮助。 |
| -n、--quiet或silent | 表示仅显示经过处理后的结果。 |
| -i | 直接编辑文本文件。 |

"操作"用于指定对文件的操作行为,就是sed的命令。常见的操作包括以下几种:

|---|-----------------------------------------------------------------------------|
| a | 增加,在当前行下面增加一行指定内容。 |
| c | 替换,将选定行替换为指定内容。 |
| d | 删除,删除选定的行。 |
| i | 插入,在选定行上面插入一行指定内容。 |
| p | 打印,如果同时指定行,表示打印指定行;如果不指定行,则表示打印所有内容;如果有非打印字符,则以 ASCII 码输出。其通常与 "-n" 选项一起使用. |
| s | 替换,替换指定字符。 |
| y | 字符转换。 |

2. 用法示例

(1) 输出符合条件的文本

#输出符合条件的文本

sed -n 'p' test.txt

#输出文件的所有内容

sed -n '3p' test.txt

#输出第3行

sed -n '3,5p' test.txt

#输出第3到5行

sed -n 'p;n' test.txt

#输出所有奇数行
sed -n '10,${n;p}' test.txt
#输出第10行至文件尾之间的偶数行

sed命令结合正则表达式时,格式略有不同,正则表达式以"/"包围。示例如下:

sed -n '/the/p' test.txt

#输出包含the的行

sed -n '4,/the/p' test.txt

#输出从第4行开始包含the的行

sed -n '/the/=' test.txt

#输出包含the的行的行号

sed -n '/^PI/p' test.txt

#输出以PI开头的行

sed -n '/\<wood\>/p' test.txt

#输出包含单词"wood"的行

(2) 删除符合条件的文本

下面命令中 nl 命令用于计算文件的行数,结合该命令可以更加直观地查看到命令执行的结果。

nl test.txt | sed '3d'

#删除第三行

nl test.txt | sed '3,5d'

#删除3到5行

nl sed '/^$/d' test.txt

#删除空格行

(3) 替换符合条件的文本

在使用sed命令进行替换操作时需要用到s(字符串替换)、c(整行/整块替换)、y(字符转换)命令选项,常见的用法如下所示:

sed 's/the/THE/' test.txt

#将每行中的第一个the替换为THE

sed 's/l/L/2' test.txt
#将每行中的第 2 个 l 替换为 L。

sed '3,5s/the/THE/' test.txt

#将第3到5行中的the替换为THE。

sed '/the/s/o/O/g' test.txt

#将包含the的所有行中的o替换为O。

(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 '3aNEW1\nNew2' test.txt

#在第3行后插入多行内容(NEW1和NEW2),中间的\n 表示换行

(5)使用脚本编辑文件

使用sed 脚本将多个编辑指令存放到文件中(每行一条编辑指令),通过 "-f" 选项来调用。例如 将第1~5行内容转移至第17行后 。这个操作可以通过使用脚本文件的方式实现。

vi opt.list
1,5H
1,5d
17G
sed -f opt.list test.txt

2.2 awk工具

在 Linux/UNIX 系统中, awk 是一个功能强大的编辑工具,逐行读取输入文本,并根据
指定的匹配模式进行查找,对符合条件的内容进行格式化输出或者过滤处理,可以在无交互
的情况下实现相当复杂的文本操作,被广泛应用于 Shell 脚本,完成各种自动化配置任务。

1. awk常见用法

通常情况下awk 所使用的命令格式如下所示,其中,单引号加上大括号 "{}" 用于设置对
数据进行的处理动作。 awk 可以直接处理目标文件,也可以通过 "-f" 读取脚本对目标文件进
行处理。

awk 选项 '模式或条件 {编辑指令}' 文件1 文件2
#过滤并输出文件中符合条件的内容
awk -f 脚本文件 文件1 文件2...

从脚本中调用编辑指令 , 过滤并输出内容

awk 比较倾向于将一行分成多个" 字段 "然后再进行处理,awk借用shell中类似于位置变量的方法, 用 1、2、$3...顺序地表示行(记录)中的不同字段。且默认情况下字段的分隔符为空格或tab 键。awk执行结果可以通过print的功能将字段数据打印显示。在使用awk命令的过程中,可以使用逻辑操作符"&&"表示"与"、"||" 表示"或"、"!"表示"非";还可以进行简单的数学运算,如+、-、*、/、%、^分别表示加、减、乘、除、取余和乘方。
awk 包含几个特殊的内建变量(可直接用)如下所示:

|----------|---------------------------|
| FS | 指定每行文本的字段分隔符,默认为空格或制表符。 |
| NF | 当前处理的行的字段个数。 |
| NR | 当前处理的行的行号(序数)。 |
| 0 | 当前处理的行的整行内容。 | | n | 当前处理行的第 n 个字段(第 n 列)。 |
| FILENAME | 被处理的文件名。 |
| RS | 数据记录分隔,默认为 \n ,即每行为一条记录。 |

2. 用法示例

awk '{print}' test.txt

#输出所有内容

awk 'NR==1,NR==3{print}' test.txt

#输出第1~3行的内容
awk '/^root/{print}' test.txt
#输出以root开头的行
awk 'BEGIN{x=0}/\/bin\/bash$/{x++};END {print x}' test.txt
#统计/bin/bash结尾的行数。

3. 按字段输出文本

awk '{print 1,3}' test.txt

#输出每行中的第1、3个字段
awk -F ":" '7\~"/bash"{print 1}' /etc/passwd
#输出以冒号分割且第7个字段中包含/bash的行的第1个字段

4. 通过管道、双引号调用Shell命令

awk 'BEGIN {while("w" | getline) n++;{print n-2}}'
#调用 w 命令 , 并用来统计在线用户数

2.3 sort工具

在linux中,常用的文件排序工具有三种:sort、uniq、wc,其中sort是一个以行为单位对文件内容进行排序的工具,也可以根据不同的数据类型来排序。sort 命令的语法为"sort 选项 参数",其中常用的选项包括以下几种:

|------------|-------------------------|
| -f | 忽略大小写; |
| -b | 忽略每行前面的空格; |
| -M | 按照月份进行排序; |
| -n | 按照数字进行排序; |
| -r | 反向排序; |
| -u | 等同于 uniq ,表示相同的数据仅显示一行; |
| -t | 指定分隔符,默认使用 Tab 键分隔; |
| -o<输出文件> | 将排序后的结果转存至指定文件; |
| -k | 指定排序区域。 |

示例:将文件中的第三行进行方向排序

复制代码
sort -t ':' -rk 3 test.txt

2.4 uniq工具

Uniq 工具在 Linux 系统中通常与 sort 命令结合使用,用于报告或者忽略文件中的重复行。

具体的语法格式为:uniq 选项 参数,其中常用选项包括以下几种:

|----|------------|
| -c | 进行计数。 |
| -d | 仅显示重复行。 |
| -u | 仅显示出现一次的行。 |

2.5 tr工具

tr命令常用来对来自标准输入的字符进行替换、压缩和删除。tr具体的命令语法格式为:
tr 选项 参数
其常用选项包括一次内容:

|----|----------------------|
| -c | 取代所有不属于指定参数的字符; |
| -d | 删除所有属于指定参数的字符; |
| -s | 把连续重复的字符以单独一个字符表示; |
| -t | 先删除第一字符集较第二字符集多出的字符。 |

示例:

echo "FKK" | tr 'A-Z' 'a-z'
#将输入字符由大写转换为小写
echo "thissss is a text linnnnnnne." | tr -s 'sn'
this is a text line.
#压缩输入中重复的字符。

相关推荐
吴声子夜歌18 小时前
正则指引——Ruby
开发语言·正则表达式·ruby
吴声子夜歌21 小时前
正则指引——Golang
开发语言·golang·正则表达式
吴声子夜歌2 天前
正则指引——PHP
开发语言·正则表达式·php
吴声子夜歌4 天前
正则指引——断言
正则表达式
吴声子夜歌4 天前
正则指引——匹配原理
java·正则表达式
吴声子夜歌5 天前
正则表达式——环视
开发语言·正则表达式
吴声子夜歌6 天前
正则表达式——边界
正则表达式
营养充电站6 天前
C++23 新特性在 CLion 中的实战体验
macos·docker·jupyter·正则表达式
吴声子夜歌6 天前
正则表达式——字符组
正则表达式