# 正则三剑客 ## 正则元字符 - `^`:两种用法: 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`的值。