# 正则三剑客
## 正则元字符
- `^`:两种用法:
1. `^[0-9]`:表示匹配以数字(也可以是字符或其他)开头的行;
2. `[^0-9]`:表示匹配非数字(也可以是字符或其他)的字符;
- `$`:以什么结尾
- `.`:用于匹配除了换行符以外的任意一个字符。
- `*`:表示前面的字符可以出现0次或多次。
- `?`:表示前面的字符可以出现0次或1次。
- `+`:表示前面的字符可以出现1次或多次。
- `{n}`:表示前面的字符必须恰好出现n次。
- `{n,}`:表示前面的字符至少出现n次。
- `{n,m}`:表示前面的字符至少出现n次,但不超过m次。
- `[]`:匹配集合中的,如:
- `[lL]ove`:匹配love并忽略l的大小写;
- `[x-y]`:匹配集合范围内的,如:
- `[0-9]`:匹配所有数字;
- `[a-z]`:所有小写字母;
- `\`:转义。将特殊含义的符号转义成普通符号。如:
- `'love\.'`:转义后的`.`不会再匹配单个字符。
- `\d`:表示匹配一个数字,等同于`[0-9]`。
- `\D`:表示匹配一个非数字字符,等同于`[^0-9]`。
- `\w`:表示匹配包括下划线的任何单词字符,等同于`[A-Za-z0-9_]`。
- `\W`:表示匹配任何非单词字符,等同于`[^A-Za-z0-9_]`。
- `\<`:以什么开头;`'\`:以什么结尾;`'love\>'`匹配以love结尾的所有行。
## grep
### 语法及选项
```
grep [选项] 查找条件 [目标文件]
-c:打印符合要求一共有多少行数;
-i:忽略大小写;
-n:输出符合要求的行及其行号;
-v:取反;
-r:遍历所有的子目录;
-A:后面跟一个数字,如-A2表示打印符合要求的行及下面的两行;
-B:后面跟一个数字,如-B2表示打印符合要求的行及上面的两行;
-C:后面跟一个数字,如-C2表示打印符合要求的行及上下各两行;
-E:使其支持扩展正则,等同于egrep。
```
扩展正则:
指的是表达式中含有:+>|(){}等符号,在grep中需要用转义符\脱义,如下3个命令等同:
```
grep '^ab\?c' 1.txt
egrep '^ab?c' 1.txt
grep -E '^ab?c' 1.txt
```
### grep选项示例
#### 过滤passwd文件中的nologin字符
```
$ grep 'nologin' passwd
```
#### -c 查看符合要求共有多少行
```
$ grep -c 'nologin' passwd
```
#### -n 显示筛选条件所在行号
```
$ grep -n 'nologin' passwd
```
#### -i 筛选忽略大小写
```
$ grep -i 'nologin' passwd
```
#### -v 取反,打印不包含nologin以外的行
```
$ grep -v 'nologin' passwd
```
#### -A2 筛选包含root的行及下面两行
```
[root@lwz1 grep]# grep -A2 'root' passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
--
operator:x:11:0:operator:/root:/sbin/nologin
games:x:12:100:games:/usr/games:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
```
### grep正则示例
#### 筛选字母l开头的行,并忽略大小写,显示行号
```
[root@lwz1 grep]# grep -n '^[lL]' passwd
5:lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
23:lwz:x:1000:1000:lwz:/home/lwz:/bin/bash
24:LWZ:x:1001:1001::/home/LWZ:/bin/bash
```
#### 筛选除大写字母L开头以外的行
```
$ grep -v '^[L]' passwd
```
#### 筛选r与o之间包含任意一个字符的行
```
[root@lwz1 grep]# grep 'r.o' passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
rao
```
> `.`:任意一个字符
> `+`:任意一个或多个字符
> `?`:0个或一个字符
#### 筛选连续出现2次o的行
```
[root@lwz1 grep]# grep -E 'o{2}' passwd
root:x:0:0:root:/root:/bin/bash
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
```
> 注意:{}中的数字表示重复的次数;
> {2,}:连续出现至少2次以上;
> {,2}:连续出现最多2次以内;
> {2,5}:连续出现2次到5次之间;
#### 同时筛选多个参数
```
[root@lwz1 grep]# grep -E 'root|nologin|lwz' passwd
root:x:0:0:root:/root:/bin/bash
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
lwz:x:1000:1000:lwz:/home/lwz:/bin/bash
```
------
## sed
sed是一种流编辑器,它一次处理一行内容。处理时,把当前处理的行存储在临时缓冲区中,称为“模式空间”,接着用sed命令处理缓冲区中的内容,处理完成后,把缓冲区的内容送往屏幕。接着处理下一行,这样不断重复,直到文件末尾。文件内容并没有改变,除非你使用重定向存储输出。
### 语法
```
sed [选项] '{命令参数}[flags]' 文件名
选项:
-e script 在命令行执行多个编辑器命令。
-f namefile 调用包含sed命令的文件来执行,批量执行是可用这种方式。
-n 抑制自动输出。
-i 编辑文件内容,可以用来删除源文件中的内容。
-i.bak 编辑文件同时创建.bak备份文件。
-r 使用扩展的正则表达式。
! 取反(gen在模式条件后与shell有所区别)
命令参数:
a 在匹配参数后面添加
i 在匹配参数前面添加
p 打印
d 删除
s 查找替换
c 更改
y 转换 N D P
flags:
数字 处理匹配到的每行中第几个结果。
g 匹配到的所有结果。
p 打印原始内容。
w filename 将处理后的结果写入指定的filename。
```
### 命令参数示例
示例文本:
```
1 the quick brown fox jumps over the lazy dog.
2 the quick brown fox jumps over the lazy dog.
3 the quick brown fox jumps over the lazy dog.
4 the quick brown fox jumps over the lazy dog.
5 the quick brown fox jumps over the lazy dog.
```
#### a 指定范围内的行下面增加内容
```
[root@lwz1 sed]# sed '2,4a\append data 'haha'' sed.txt
1 the quick brown fox jumps over the lazy dog.
2 the quick brown fox jumps over the lazy dog.
append data haha
3 the quick brown fox jumps over the lazy dog.
append data haha
4 the quick brown fox jumps over the lazy dog.
append data haha
5 the quick brown fox jumps over the lazy dog.
```
> 说明:`a`表示在匹配的行下面新增内容。`2,4a`表示2到4行,如果不写数字,表示匹配所有行。`\`转义符可以不写,写上方便查看。
```
# 匹配包含指定字符串的行下面新增内容
[root@lwz1 sed]# sed '/3 the/a\append data ' sed.txt
1 the quick brown fox jumps over the lazy dog.
2 the quick brown fox jumps over the lazy dog.
3 the quick brown fox jumps over the lazy dog.
append data
4 the quick brown fox jumps over the lazy dog.
5 the quick brown fox jumps over the lazy dog.
```
> 说明:`sed '/要匹配的字符串/a\要新增的内容' 文件名`
#### i 匹配包含指定字符串的行上面新增内容
```
[root@lwz1 sed]# sed '/5 the/i\append data' sed.txt
1 the quick brown fox jumps over the lazy dog.
2 the quick brown fox jumps over the lazy dog.
3 the quick brown fox jumps over the lazy dog.
4 the quick brown fox jumps over the lazy dog.
append data
5 the quick brown fox jumps over the lazy dog.
```
#### s 替换指定范围行中的指定字符串
```
[root@lwz1 sed]# sed '2,4s/dog/cat/' sed.txt
1 the quick brown fox jumps over the lazy dog.
2 the quick brown fox jumps over the lazy cat.
3 the quick brown fox jumps over the lazy cat.
4 the quick brown fox jumps over the lazy cat.
5 the quick brown fox jumps over the lazy dog.
```
> `sed '指定范围s/被替换/替换后/' 文件名`
> 如果指定字符串为定义行:`sed '/3 the/s/dog/cat/' 文件名`
#### c 替换匹配到的行内容
```
[root@lwz1 sed]# sed '2,4cchange data haha' sed.txt
1 the quick brown fox jumps over the lazy dog.
change data haha
5 the quick brown fox jumps over the lazy dog.
[root@lwz1 sed]# sed '2,4c\change data haha' sed.txt # 两种写法都可。
```
#### y 字符转换,将内容中的a b c转换为大写
```
[root@lwz1 sed]# sed 'y/abc/ABC/' sed.txt
1 the quiCk Brown fox jumps over the lAzy dog.
2 the quiCk Brown fox jumps over the lAzy dog.
```
> 说明:也可以转换为其他的任意单个字符
#### d 删除整行
```
[root@lwz1 sed]# sed '1,4d' sed.txt
5 the quick brown fox jumps over the lazy dog.
```
#### p 打印输出
```
[root@lwz1 sed]# sed '/2 the/p' sed.txt
1 the quick brown fox jumps over the lazy dog.
2 the quick brown fox jumps over the lazy dog.
2 the quick brown fox jumps over the lazy dog.
3 the quick brown fox jumps over the lazy dog.
```
> 说明:sed默认会打印。原因是打印了指定文件内容一次,又将读入缓存的所有数据打印了一次,所以会看到这样的效果,加上选项`-n`可以避免。
打印指定字符串开头的行
```
[root@lwz1 sed]# sed '/2 the/p' sed.txt -n
2 the quick brown fox jumps over the lazy dog.
```
指定打印12和13行的内容
```
sed -n '12,13p' sed.txt
```
### 选项示例
#### -e 同时执行多个命令
```
[root@lwz1 sed]# sed -e 's/brown/green/' -e 's/dog/cat/' sed.txt
[root@lwz1 sed]# sed -e 's/brown/green/;s/dog/cat/' sed.txt # 两条命令效果相同。
1 the quick green fox jumps over the lazy cat.
2 the quick green fox jumps over the lazy cat.
```
#### -f 从文件读取编辑器命令
适用于日常重复执行的场景
```
[root@lwz1 sed]# vi abc.txt # 创建一个包含sed命令的文件
1s/brown/green/
2y/abc/ABC/
3c\linyi
4a\123
[root@lwz1 sed]# sed -f abc.txt sed.txt # 使用-f选项调用
1 the quick green fox jumps over the lazy dog.
2 the quiCk Brown fox jumps over the lAzy dog.
linyi
4 the quick brown fox jumps over the lazy dog.
123
5 the quick brown fox jumps over the lazy dog.
```
#### -i.bak 修改文件内容,并将源文件备份成.bak
```
[root@lwz1 sed]# sed -i.bak 's/dog/cat/' sed.txt # 加上-i.bak选项
[root@lwz1 sed]# cat sed.txt # 替换后的文件
1 the quick brown fox jumps over the lazy cat.
[root@lwz1 sed]# cat sed.txt.bak # 备份的源文件
1 the quick brown fox jumps over the lazy dog.
```
### -r 正则示例
`/key/`查询匹配关键字的行
```
[root@lwz1 sed]# sed -n '/cat/p' sed.txt
```
`/key1/,/key2/`匹配两个关键字之间的行
```
[root@lwz1 sed]# sed -n '/^3/,/^cat/p' sed.txt
```
`/key/,x`从匹配关键字的行开始到文件第x行之间的行(包含关键字所在行)
```
[root@lwz1 sed]# sed -n '/^3 the/,7p' sed.txt
```
`x,/key/`从文件的第x行开始到与关键字的匹配之间的行
```
[root@lwz1 sed]# sed -n '3,/cat$/p' sed.txt
```
`x,y!`不包含x到y的行
```
[root@lwz1 sed]# sed -n '3,4!p' sed.txt
1 the quick brown fox jumps over the lazy cat.
2 the quick brown fox jumps over the lazy cat.
5 the quick brown fox jumps over the lazy cat.
```
`/key/!`不包含关键字的行
```
[root@lwz1 sed]# sed -n '/cat$/!p' sed.txt # 不以cat结尾的行
```
### flags示例
示例文件
```
[root@lwz1 sed]# vi flags.txt
1 the quick brown fox jumps over the lazy dog . dog
2 the quick brown fox jumps over the lazy dog . dog
3 the quick brown fox jumps over the lazy dog . dog
```
#### d 删除范围内的行
```
[root@lwz1 sed]# sed -i '4,5d' flags.txt # 删除源文件4行到5行
```
#### 数字2 替换每行中第二次匹配到的关键字
```
[root@lwz1 sed]# sed 's/dog/cat/2' flags.txt
1 the quick brown fox jumps over the lazy dog . cat
2 the quick brown fox jumps over the lazy dog . cat
```
> 说明:s参数默认只替换每行中第一次匹配到的关键字
#### g 匹配行中所有关键字
```
[root@lwz1 sed]# sed '/3 the/s/dog/cat/g' flags.txt
1 the quick brown fox jumps over the lazy dog . dog
2 the quick brown fox jumps over the lazy dog . dog
3 the quick brown fox jumps over the lazy cat . cat
```
#### w 将修改后的内容存入指定文件中
```
[root@lwz1 sed]# sed '3s/dog/cat/w w.txt' flags.txt
1 the quick brown fox jumps over the lazy dog . dog
2 the quick brown fox jumps over the lazy dog . dog
3 the quick brown fox jumps over the lazy cat . dog
[root@lwz1 sed]# cat w.txt
3 the quick brown fox jumps over the lazy cat . dog
```
### sed小技巧
#### 统计文件有多少行
```
# 一共多少行
[root@lwz1 sed]# sed -n '$=' /etc/passwd
24
# 显示行号并输出内容
[root@lwz1 sed]# sed '=' /etc/passwd
# 查看关键字行号
[root@lwz1 sed]# sed '/lwz/=' /etc/passwd -n
```
#### 以某某结尾或者开头的行
```
# 数字开头的行
[root@lwz1 sed]# sed '/^[0-9]/p' sed.txt -n
1 the quick brown fox jumps over the lazy cat.
# c或者h结尾的行
[root@lwz1 sed]# sed '/[c,h]$/p' /etc/passwd -n
root:x:0:0:root:/root:/bin/bash
sync:x:5:0:sync:/sbin:/bin/sync
lwz:x:1000:1000:lwz:/home/lwz:/bin/bash
LWZ:x:1001:1001::/home/LWZ:/bin/bash
```
#### 开头或末尾添加或删除
```
# 文件中2到4行开头添加#,可以用于脚本注释
[root@lwz1 sed]# sed '2,4s/^/#/' sed.txt
1 the quick brown fox jumps over the lazy cat.
#2 the quick brown fox jumps over the lazy cat.
#3 the quick brown fox jumps over the lazy cat.
#4 the quick brown fox jumps over the lazy cat.
5 the quick brown fox jumps over the lazy cat.
# 将文件中不以#开头的行的行首添加#
[root@lwz1 sed]# sed 's/^[^#]/#&/' sed.txt
# 删除文件中所有以#开头,后面至少跟一个空白字符的行的行首的#和空白字符
[root@lwz1 sed]# sed 's/^#[[:space:]]*//' sed.txt
# 匹配2,5行中以#开头的行,并将#替换为空,类似删除
[root@lwz1 sed]# sed '2,5s/^#//' sed.txt # 如果不定义以#开头的话,第5行中的#也会被删除。
1 the quick brown fox jumps over the lazy cat.
2 the quick brown fox jumps over the lazy cat.
3 the quick brown fox jumps over the lazy cat.
4 the quick brown fox jumps over the lazy cat.
5# the quick brown fox jumps over the lazy cat.
# 匹配包含cat关键词的所有行,并将结尾的#替换为空,类似删除
[root@lwz1 sed]# sed '/cat/s/#$//' sed.txt
```
----------------------
## awk
### 语法
```
awk [选项] 'BEGIN{commands} pattern{commands} END{commands}' filename
选项:
-F:指定内容中的分隔符(默认空格)
-v:赋值用户自定义的变量
-f:指定脚本文件,从脚本中读取awk命令
BEGIN{commands}:开始块,awk数据处理前执行的命令(可选),在语句中只执行一次。BEGIN必须大写。可用作:
1.设置变量计数起始值。
2.打印头部信息。
3.改变字段的分隔符。
4.打开文件。
END{commands}:结束块。awk数据处理后执行的命令(可选),在语句中只执行一次。END必须大写。语句:
1.输出统计的结果。
2.打印结尾信息。
3.关闭文件。
pattern{commands}:对文件的每一行遍历,判断是否满足pattern的模式,如果满足则执行脚本。
内置变量:
$n:列的内容。例如:$1表示第一列、$2表示第二列。
$0:行的内容。
FILENAME:当前输入的文件名。
FS:指定字段分隔符(默认是空格)
NF:字段数,在执行过程中对应于当前的字段数,NF:列的个数。
NR:显示行号,或者指定某行。
FNR:各文件分别计数的行号。
OFS:指定内容输出时字段的分隔符(默认空格)
ORS:指定内容输出时行的分隔符(默认换行符)
RS:行分隔符(默认换行符)
~:匹配
!~:不匹配
\n:换行符
正则表达式:
/root/:匹配包含root的行。
关系表达式:
<:小于;<=:小于等于。
>:大于;>=:大于等于。
&&:逻辑与,两个条件同时成立,则为真。
||:逻辑或。两个条件中成立一项,则为真。
+:数值相加。
*:数值相乘。
匹配表达式:
~:匹配。
!~:不匹配。
==:等于,精确匹配。
!=:不等于。
```
awk的工作流程:
1. 读:从文件、管道或者标准输入中读入一行然后把它存放到内存中。
2. 执行:根据awk命令按顺序执行读取到的行数据。
3. 重复:一直重复上述两个过程直到文件结束。
### 示例
#### -F 指定分隔符,并打印第一段
```
[root@lwz1 sed]# awk -F: '{print $1}' passwd.txt
```
#### 打印所有行内容
```
[root@lwz1 sed]# awk '{print $0}' passwd.txt
```
#### 匹配字符或者字符串
打印包含oo的所有行。
```
[root@lwz1 sed]# awk '/oo/ {print $0}' passwd.txt
root:x:0:0:root:/root:/bin/bash
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
```
第一段中包含oo的行
```
[root@lwz1 sed]# awk -F: '$1~/oo/' passwd.txt
root:x:0:0:root:/root:/bin/bash
或者
[root@lwz1 sed]# awk -F: '$1~/oo/ {print $0}' passwd.txt
```
多个匹配条件
```
[root@lwz1 sed]# awk -F: '/root/ {print $1,$3} /bash/ {print $1,$3,$7}' passwd.txt
root 0
root 0 /bin/bash
operator 11
lwz 1000 /bin/bash
LWZ 1001 /bin/bash
```
> 说明:-F指定分隔符为`:`,打印文本中包含`root`的行的第一段和第三段,包含`bash`的行的第一、三、七段。
#### 条件匹配与判断
精确匹配第三段中等于0的行
```
[root@lwz1 sed]# awk -F: '$3==0' passwd.txt
root:x:0:0:root:/root:/bin/bash
```
判断第三段中大于等于500的行
```
[root@lwz1 sed]# awk -F: '$3>=500' passwd.txt
nobody:x:65534:65534:Kernel Overflow User:/:/sbin/nologin
systemd-coredump:x:999:997:systemd Core Dumper:/:/sbin/nologin
polkitd:x:998:996:User for polkitd:/:/sbin/nologin
```
判断第三段小于第四段的行
```
[root@lwz1 sed]# awk -F: '$3<$4' passwd.txt
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
```
`||`逻辑或的用法
```
[root@lwz1 sed]# awk -F: '$3>100 || $7=="/sbin/nologin"' passwd.txt
bin:x:1:1:bin:/bin:/sbin/nologin # 第七段等于/sbin/nologin成立。
daemon:x:2:2:daemon:/sbin:/sbin/nologin
lwz:x:1000:1000:lwz:/home/lwz:/bin/bash # 第三段大于100成立。
```
`&&`逻辑与的用法
```
[root@lwz1 sed]# awk -F: '$1=="lwz" && $3 ~ 0' passwd.txt
lwz:x:1000:1000:lwz:/home/lwz:/bin/bash
```
> 说明:第一段为lwz,并且第三段包含0的行同时达成,则匹配。
#### 内置变量用法
##### `OFS`指定分隔符用法:
```
[root@lwz1 sed]# awk -F: '{OFS="#"} $3>1000 || $7~/bash/ {print $1,$3,$7}' passwd.txt
root#0#/bin/bash
nobody#65534#/sbin/nologin
# 或者使用如下方法
[root@lwz1 sed]# awk -F: '$3>1000 || $7~/bash/ {print $1"~"$3"~"$7}' passwd.txt
root~0~/bin/bash
nobody~65534~/sbin/nologin
```
> 说明:`OFS`指定分隔符为`#`,在匹配`||`两边的条件,符合一项则成立。
##### `NR`表示行,用法:
```
# 用NR显示行号
[root@lwz1 sed]# awk '{print NR":"$0}' passwd.txt
# NR匹配前3行,打印并显示行号
[root@lwz1 sed]# awk -F: 'NR<=3 {print NR,$0}' passwd.txt
1 root:x:0:0:root:/root:/bin/bash
2 bin:x:1:1:bin:/bin:/sbin/nologin
3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
# 匹配前3行中包含root和daemon的行
[root@lwz1 sed]# awk -F: 'NR<=3 && $0~/root|daemon/' passwd.txt
root:x:0:0:root:/root:/bin/bash
daemon:x:2:2:daemon:/sbin:/sbin/nologin
```
##### `NF`表示段,用法:
```
# 显示每一行有多少段
[root@lwz1 sed]# awk -F: '{print NF":"$0}' passwd.txt
7:root:x:0:0:root:/root:/bin/bash
```
#### 数学运算符用法
更改某一段的值:
```
[root@lwz1 sed]# head -n 3 passwd.txt | awk -F: '$1="root"'
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的共有哪些行:
```
[root@lwz1 sed]# awk -F: '$1=="root"' passwd.txt
root:x:0:0:root:/root:/bin/bash
```
计算某一段的总和:
```
[root@lwz1 sed]# awk -F: '{tot=tot+$3} END {print tot}' passwd.txt
73000
```
> 说明:`tot`在awk中表示累加器,用来存储和累加某个变量的值,累加器默认从0开始;`tot=tot+$3`表示将`$3`的值累加到`tot`中。这里使用`END`表示只输出最后`tot`的值。