0%

linux运维学习笔记:正则表达式

写在前面

这则笔记整理正则表达式的相关内容,正则表达式 Regular expressions 被用来根据某种匹配模式来寻找strings中的某些单词。主要包括以下内容:

  • 正则表达式基础

  • grep

  • sed

  • awk

正则表达式基础

正则表达式,是经过专门编写的文本字符串,用来匹配字符串,这里还整理了一篇正则基础

元字符

表达式 描述
. 匹配单个任意字符
[] 匹配指定范围内的任意单个字符,比如[abc],[a-z],[0-9],[a-zA-Z]
[^] 取非,匹配指定范围外的任意单个字符
[:space:] 匹配空白字符
[:punct:] 匹配所有标点符号的集合
[a-z][:lower:] 匹配所有的小写字母
[A-Z][:upper:] 匹配所有的大写字母
[a-zA-Z][:alpha:] 匹配大小写字母
[0-9][:digit:] 匹配数字
[0-9a-zA-Z][:alnum:] 匹配数字和大小写字母

匹配次数

表达式 描述
* 匹配其前面的字符任意次,比如.*匹配任意字符任意次数
\? 匹配其前面的字符1次或0次
\{m,n\} 匹配其前字符最少m,最多n次)

匹配单词

如果我们想要找到字符串The dog chased the cat中单词 the,我们可以使用下面的正则表达式:

1
/the/gi

这个正则表达式分成几段:

  • / 是这个正则表达式的头部

  • the 是我们想要匹配的模式

  • / 是这个正则表达式的尾部

  • g 代表着 global(全局),意味着返回所有的匹配而不仅仅是第一个。

  • i 代表着忽略大小写,意思是当我们寻找匹配的字符串的时候忽略掉字母的大小写。

匹配数字

在正则表达式中使用特殊选择器来选取特殊类型的值。其中之一就是数字选择器\d,意思是被用来获取一个字符串的数字。

1
/\d/g

在选择器后面添加一个加号标记(+),例如:/\d+/g,它允许这个正则表达式匹配一个或更多数字。

尾部的g是’global’的简写,意思是允许这个正则表达式 找到所有的匹配而不是仅仅找到第一个匹配。

匹配空白

使用正则表达式选择器 \s 来选择一个字符串中的空白。

1
/\s+/g

注:空白字符有 “ “ (空格符)、\r (回车符)、\n (换行符)、\t (制表符) 和 \f (换页符)。

匹配非空白字符

可以用正则表达式选择器的大写版本 来转化任何匹配。例如,\s 匹配任何空白字符,\S 匹配任何非空白字符。

1
2
3
4
5
6
7
8
9
10
11
// 初始化变量
var testString = "How many non-space characters are there in this sentence?";

// 请只修改这条注释以下的代码

var expression = /\S/g; // 请修改这一行

// 请只修改这条注释以上的代码

// 用 nonSpaceCount 存储 testString 中匹配到 expression 的次数
var nonSpaceCount = testString.match(expression).length;

配合位置

  • ^ 匹配字符串开头
  • $ 匹配字符串结尾
  • \b 匹配单词的起始终止位置

示例:

1
2
3
4
5
^\d{5,12}$  // 匹配5-12位的QQ号码 

\ba\w*\b //匹配以字母a开头的单词(w*表示任意数量的字母或数字)

\b\w{6}\b //匹配刚好6个字符的单词

字符转义

如果想查找元字符本身,需要使用\来取消这些字符的特殊意义。
示例:

1
2
deerchao\.net   //匹配deerchao.net
C:\\Windows //匹配C:\Windows

匹配次数

代码/语法 说明
* 重复零次或更多次
+ 重复一次或更多次
? 重复零次或一次
{n} 重复n次
{n,} 重复n次或更多次
{n,m} 重复n到m次

常用的反义代码

查找不属于某个能简单定义的字符类的字符

代码/语法 说明
\W 匹配任意不是字母,数字,下划线,汉字的字符
\S 匹配任意不是空白符的字符
\D 匹配任意非数字的字符
\B 匹配不是单词开头或结束的位置
[^x] 匹配除了x以外的任意字符
[^aeiou] 匹配除了aeiou这几个字母以外的任意字符

字符锚定

表达式 描述
^ 锚定行首,此字符后面的任意内容必须出现在行首
$ 锚定行尾,此字符前面的任意内容必须出现在行尾
^$ 锚定空白行,可以统计空白行
\<\b 锚定词首,其后面的任意字符必须做为单词首部出现
\>\b 锚定词尾,其前面的任意字符必须做为单词尾部出现

拓展正则表达式

相比于基础正则表达式,拓展正则表达式的不同之处主要在于以下几点:

  1. 在匹配次数方面,加入了 + ,表示匹配字符出现一次或多次;

  2. 基本正则表达式,使用( ) { } . ? |都需要转义,在扩展正则表达中不需要加转义符 \

  3. |表示或者的意思。

grepegrep 命令

grep

grep是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹配的行打印出来。

命令行格式:grep [参数] [关键词] [filename]

常用参数 用法
-c 打印符合要求的行数
-i 忽略大小写
-n 输出符合要求的行及行号
-v 取反
-r 归递处理,包含多级子目录
-l 查询多文件时只输出包含匹配字符的文件名
-A n n 为数字,打印符合条件的行及后面n行
-B n n 为数字,打印符合条件的行及前面n行
-C n n 为数字,打印符合条件的行及前、后各n行

常见用法

  • 匹配符合要求的行数grep -c 'keyword'

  • 搜索/etc目录及其多级子目录 grep -r /etc

  • 搜索当前目录下包含‘500’ 的文件名
1
ls | grep -rl '500'
  • 匹配带有关键词的行,并输出行号 grep -n 'keyword'

  • 匹配不带有关键词的行,并输出行号 grep -v 'keyword'

  • 匹配包括数字的行 grep '[0-9]'

  • 匹配不包括数字的行 grep -v '[0-9]'

  • 匹配大写字母 grep [A-Z]grep [[:upper:]]

  • 匹配单行包含空格的内容 grep [[:space:]]

  • 匹配单行包含标点符号的内容 grep [[:punct:]]

匹配单行包含数字和大小写字母的内容 grep [0-9a-z-A-Z]grep [[:alnum:]]

  • 匹配所有以#开头的行,并显示行号 grep -n '^#' 注:包括空行。

  • 匹配所有的非空行和不以#开头的行 grep -vn '^#'

  • 匹配任意一个字符 grep -n 'ro.t' .表示任意字符
1
2
[root@stevey ~]# cat a.txt | grep -n 'ro.t'
3:root:x:0:0:root:/root:/bin/bash
  • 匹配任意多个字符 .* 表示0个或多个任意字符;

  • 匹配特定重复次数的字符

此处需要用{},其中为数字,表示为{n}{m, n}。其中 {n}表示特定次数;{m, n} 表示范围,m < n

注: {}前后都要使用转义符号\;如果不想使用脱义符号,使用grep -E 或者egrep

{n}表示特定次数;

{m,n} 表示范围,m < n

n可以省略,表示m以上

m也可以省略,表示n次及以下

ABC特殊参数用法

  • -A n n为数字,打印符合条件的行及后面n

  • -B n n 为数字,打印符合条件的行及前面n

  • -C n n 为数字,打印符合条件的行及前、后各n

egrep 命令: grep 命令的升级版

egrepgrep 的升级版,使用拓展式的正则表达式,与grep -E的效果相同。

  • + 匹配一个或多个字符

  • ? 匹配0个或1个字符

  • | 表示或者,表示二选一或者多选一,满足其中一个就可以

  • ()表示一个整体, 比如(oo)+, 匹配oo 出现一次或一次以上

sed 命令

sed,全称是stream editor,流编辑器,也是用来进行文本处理的工具。对比grep ,他的强大之处,不仅能够用来匹配文档内容,还能够进行修改。

sed在执行的时候,会从文件或者标准输入中读取一行,将其复制到缓冲区,对文本编辑完成之后,读取下一行直到所有的文本行都编辑完毕。

所以sed命令处理时只会改变缓冲区中文本的副本,如果想要直接编辑原文件,可以使用-i选项或者将结果重定向到新的文件中。

sed 命令行格式: sed [参数] [command] [文件名]

参数 作用
-n 取消默认输出,不打印不符合要求的行
p 将选择的数据列出来,通常用 -n 连用
-d 删除
-e 多点编辑,可以执行多个子命令
-f 从脚本文件中读取命令(sed操作可以事先写入脚本,然后通过-f读取并执行)
-i 直接编辑原文件
-l 指定行的长度
-r 在脚本中使用扩展正则表达式,与grep -E作用类似
s 用一个字符串替换另一个
w 写入
a\ 追加到目标行之下
i\ 追加到目标行之上

示例:

文本匹配 (与grep 类似)

  • 打印指定的某一行 sed -n 'n'p [filename] 注:’n’和p之间没有空格
1
2
[root@stevey ~]# sed -n '2'p a.txt
dvdvcfdv
  • 打印范围,指定的某几行 sed -n 'm,n'p [filename]
1
2
3
4
[root@stevey ~]# sed -n '1,3'p a.txt   //打印第一行至第三行
#cewfef
dvdvcfdv
fewfawef
  • 打印包含某个字符的行 sed -n '/keyword/'p [filename]
1
2
3
[root@stevey ~]# sed -n '/root/'p a.txt
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
  • 在grep中使用的 . * ^ $ ,同样也可以在sed中使用
1
2
3
4
5
6
[root@stevey ~]# sed -n '/ro.t/'p a.txt
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin

[root@stevey ~]# sed -n '/^#/'p a.txt
#cewfef
  • 匹配多个command sed -e '2'p -e '/sbin/'p a.txt 只要符合条件之一就会打印出来
1
2
3
4
5
6
[root@stevey ~]# sed -n -e '2'p -e '/sbin/'p a.txt
dvdvcfdv
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
  • 匹配首行到末行 sed -n '1,$'p $表示行尾

文本编辑

d 删除指定内容

注:这里文档内容实际上并没有被删除,如果确实需要删除,还需要采取输出重定向或者使用-i选项。

  • 删除第一行内容sed 'n'd [filename] n为数字

  • 删除空白行 sed '/^$/d' [filename]

  • 删除文件最后一行 sed '$'d [filename]

  • 删除文件中所有开头是root的行 sed '/^root/'d [filename]

  • 删除文件的第2行到末尾所有行 sed '2,$'d [filename]
1
2
[root@stevey ~]# head a.txt | sed '2,$'d   //此处删除了第2至10行的内容
#cewfef

替换文档内容 sed 'm,ns/keyword/替换文字/g' [filename]

注:

  1. 此处的mn,代表数字,表示替换范围;

  2. s表示替换动作,sn之间没有空格;

  3. g表示本行所有的keyword全局替换;如果不加g,则只替换本行第一个keyword

  4. / 还可以用# 或者 @ 代替

写入文档

  • w选项:file1 中包含 keyword内容都会被写入file2 sed -n '/root/w [file2]' [file1]
1
2
3
4
[root@stevey ~]# sed -n '/root/w b.txt' a.txt
[root@stevey ~]# cat b.txt
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
  • a\ : 指定内容追加到keyword 所在行后面 sed '/^keyword/a\追加内容' file

  • 第2行之后插入 this is a test

  • i\ : 指定内容插入到keyword所在行之前

  • 第5行之前插入 linux is blablabla

-i 直接编辑修改原文件

注: 用前面提到的替换文档内容不同,加上 -i选项,就会直接更改原始文件

调换字符串位置

  • 对字段进行排序 sed -r 's/([^:]+):(.*):([^:]+)/\3:\2:\1/'
1
2
3
4
[root@stevey ~]# head -n 3 a.txt | sed -r 's/([^:]+):(.*):([^:]+)/\3:\2:\1:/'
/bin/bash:x:0:0:root:/root:root:
/sbin/nologin:x:1:1:bin:/bin:bin:
/sbin/nologin:x:2:2:daemon:/sbin:daemon:

注:

  1. -r 表示在脚本中使用扩展正则表达式,与grep -E作用类似;如果不使用-r ,就需要使用脱义符

  2. ()表示分组,如上所述,实际上分为了三组;后面的\3、\2、\1表示分组的排序;

  • 删除字符串,只保留数字 sed -r 's/[a-zA-Z]//g'

  • 在所有行的前面加上一个字符串aaa sed -r 's/(.*)/aaa:&/'

awk 命令

awk 也是流式编辑器,用来进行高级文本处理,支持关联数组、归递函数、条件语句等。

语法结构

第一种:awk [选项参数] 'script' file(s)

在这种格式中,awk从一个或多个文件中读取内容,之后再用引号里的script进行处理。

[选项参数] 这里一般是-F 后面跟分割符,比如/etc/passwd,字段与字段之间使用分割,处理时就要写成 -F ':';如果不加 -F 默认使用空格分割。

再来说后面script的部分,awk 之所以能够进行高级文本处理,是因为这里的script可以很复杂,通常可分为三个可选的部分:BEGIN、BODY和END。

awk的工作方式:

  1. 执行BEGIN 语句块;这是一个可选语句块,例如变量初始化、打印输出表格的表头等通常都放在这里面。

  2. BODY通常包含两个部分:pattern和action;awk在执行完BEGIN语句之后,会逐行读取file内容,就像一个for循环,每读一行先按照前面的pattern进行匹配,如果匹配则执行后面的action;重复这个过程,一直到文件内容全部读完。

  3. 执行END语句块;跟BEGIN类似,也是可选的。

注:在第二步中的的action 是可以省略的;如果省略action,则默认执行{ print },也就是把所有符合pattern的内容都打印在屏幕上。

第二种:awk [选项参数] -f script-file file(s)

在这种格式中,script被写进脚本文件里,在执行的时候,awk 命令会从脚本文件中读取script,在按照方式一中的步骤进行操作。这则笔记暂不涉及这种用法。

awk 基本操作

匹配字符串

  • 先来看最基本的用法:从/etc/passwd 中匹配出含有root 的行;前文说到,script的部分中,BEGIN、END都是可选的,这里都省略了,中间包括了-F指定分割符,以及BODY中的pattern,省略了action,默认执行{print},打印出了匹配pattern的行。
1
2
3
[root@stevey ~]# cat /etc/passwd | awk -F ':' '/root/'
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
  • 再复杂一点,可以切割之后匹配关键词;例如,在在第一段中匹配包含keyword的行,$1 表示第一个字段,~代表匹配的意思
1
2
3
4
[root@stevey ~]# awk -F ':' '$1 ~/ro/' a.txt  
root:x:0:0:root:/root:/bin/bash
[root@stevey ~]# awk -F ':' '$1 ~/oo/' a.txt
root:x:0:0:root:/root:/bin/bash

关于-F选项,后面跟指定的分割符;如不加 -F选项,默认以空格或tab为分隔符;print表示打印,要用{} 括起来,$1表示第一列,$2表示第二列,以此类推;

  • {print $n}用来指定打印区域;$n n表示数字,用来制定域;$0 很特殊,表示所有的段;
1
2
3
4
5
[root@stevey ~]# cat /etc/passwd |awk -F ':' '$1 ~/root/ {print $1}'     //这里只将第一字段显示出来
root

[root@stevey ~]# cat /etc/passwd |awk -F ':' '$1 ~/root/ {print $0}' //$0表示显示整行
root:x:0:0:root:/root:/bin/bash
  • 多次匹配 awk -F ':' '/keyword/{打印区域} /keyword/ {打印区域}' [filename]
1
2
3
4
5
6
[root@stevey ~]# head -n 5 a.txt | awk -F ':' '/root/ {print $1,$3} /sbin/ {print $0}'
root 0
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin

条件操作符

awk命令支持用逻辑符号进行匹配,

符号 含义
== 等于
!= 不等于
> 大于
< 小于
>= 大于等于
<= 小于等于

注:在于数字做比较时,加引号,则视为字符串;不加引号,则视为数字。

  • 匹配uid大于500的行
1
2
3
4
5
[root@stevey ~]# awk -F ':' '$3 > 500' a.txt    //匹配uid大于500的内容
polkitd:x:999:997:User for polkitd:/:/sbin/nologin
user1:x:1000:1000::/home/user1:/bin/bash
user2:x:1001:1001::/home/user2:/bin/bash
yuanfeng:x:1002:1002::/home/yuanfeng:/bin/bash
  • 匹配uid等于1000的行,这里相当于精确匹配
1
2
[root@stevey ~]# awk -F ':' '$3 == 1000' a.txt    //== 表示等于,相当于精确匹配
user1:x:1000:1000::/home/user1:/bin/bash
  • 匹配第七列不是’/bin/bash’ 的行,!=表示取非的意思。
1
2
3
4
5
6
7
[root@stevey ~]# awk -F ':' '$7 !=/bin/bash' a.txt
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
  • awk 还可以对两列内容比较逻辑关系
1
2
3
4
5
6
[root@stevey ~]# awk -F ':' '$3 < $4' a.txt
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
games:x:12:100:games:/usr/games:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
  • 比较两个字段是否精确比较
1
2
3
4
5
6
[root@stevey ~]# awk -F ':' '$3 == $4 ' a.txt
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
nobody:x:99:99:Nobody:/:/sbin/nologin
systemd-network:x:192:192:systemd Network
  • 支持&&,表示且的意思,两个条件都满足。
1
2
[root@stevey ~]# awk -F ':' '$3 > 5 && $3 < 7' a.txt
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
  • 支持 ||,表示或的意思,两个条件满足其一。
1
2
3
[root@stevey ~]# awk -F ':' '$3 > 1000 || $4 == "/bin/bash"' a.txt
user2:x:1001:1001::/home/user2:/bin/bash
yuanfeng:x:1002:1002::/home/yuanfeng:/bin/bash\

awk 内置变量

内置变量 含义
$0 当前记录(这个变量中存放着整个行的内容)
$1~$n 当前记录的第n个字段,字段间由FS分隔
FS 输入字段分隔符 默认是空格或Tab
NF 当前记录中的字段个数,就是有多少列
NR 已经读出的记录数,就是行号,从1开始,如果有多个文件话,这个值也是不断累加中。
FNR 当前记录数,与NR不同的是,这个值会是各个文件自己的行号
RS 输入的记录分隔符, 默认为换行符
OFS 输出字段分隔符, 默认也是空格
ORS 输出的记录分隔符,默认为换行符
FILENAME 当前输入文件的名字

内置变量的用法示例

  • OFS 用法
1
2
3
4
5
6
7
8
9
10
[root@stevey ~]# awk -F ':' '{OFS="#"} {print $1, $3, $4}' a.txt
root#0#0
bin#1#1
daemon#2#2
adm#3#4
lp#4#7
sync#5#0
shutdown#6#0
halt#7#0
mail#8#12
  • NR表示行号;NF表示有多少列, $NF 表示最后一个字段的值
1
2
3
4
5
6
7
8
[root@stevey ~]# head -n 3 a.txt | awk -F ':' '{print NF}'
7
7
7
[root@stevey ~]# head -n 3 a.txt | awk -F ':' '{print $NF}'
/bin/bash
/sbin/nologin
/sbin/nologin

awk中的数学计算

  • 对指定字段赋值
1
2
3
4
5
6
7
8
[root@stevey ~]# awk -F ':' '{$1="root";print $0}' a.txt
root x 0 0 root /root /bin/bash
root x 1 1 bin /bin /sbin/nologin
root x 2 2 daemon /sbin /sbin/nologin
root x 3 4 adm /var/adm /sbin/nologin
root x 4 7 lp /var/spool/lpd /sbin/nologin
root x 5 0 sync /sbin /bin/sync
root x 6 0 shutdown /sbin /sbin/shutdown
  • 将指定字段的值进行数学运算后,赋给另一个字段
1
2
3
[root@stevey ~]# head -n 2 a.txt | awk -F ':' '{$7=$3+$4; print $0}'    //$7被重新赋值,等于$3、$4相加之和。
root x 0 0 root /root 0
bin x 1 1 bin /bin 2

更多教程

-------------本文结束感谢您的阅读-------------
坚持原创技术分享,您的支持将鼓励我继续创作!