目录
一、正则表达式
1.1用法
1.2表示字符匹配
1.3表示次数
1.4表示位置锚定
1.5表示分组或其他
1.6扩展正则表达式
二、grep命令
三、awk命令
3.1awk与vim的区别
3.2awk的语法
3.3基础用法
test1.提取磁盘的分区利用率
test2.提取用户名和uid号
test3.提取ip地址
编辑 test4.awk的统计用法
3.4常见的内置变量
关于FS的使用
关于OFS的使用
关于RS的使用 :为换行符
关于NF的使用 :表示最后一列
关于NR的使用 :表示行号
3.5模式
第一种:模式为空,直接处理
第二种:模式为正则表达式
第三种:NR行范围(前面已经写过了)
第四种:内置变量值比较
3.6关系表达式(扩展)
3.7条件判断
3.8awk中的for循环
3.9数组
3.10awk 脚本
REGEXP: Regular Expressions,由一类特殊字符及文本字符所编写的模式,其中有些字符(元字符)不表示字符字面意义,而表示控制或通配的功能,类似于增强版的通配符功能,但与通配符不同,通配符功能是用来处理文件名,而正则表达式是处理文本内容中字符。
正则表达式被很多程序和开发语言所广泛支持:vim, less,grep,sed,awk, nginx,mysql 等
在bash环境下,正则表达式与通配符的区别:
正则表达式:是匹配字符串(命令结果,文本内容) ,一般与文本三剑客一起使用
通配符:匹配文件名(而是已经存在的文件),一般与find一起使用
元字符,就是有特殊含义的字符
元字符 | 含义 |
. | 匹配任意单个字符,可以是一个汉字 |
[] | 匹配指定范围内的任意单个字符,示例:[zhou],[0-9],[a-zA-Z] |
[^] | 匹配指定范围外的任意单个字符,示例:[^zhou] [^a.z] |
[:alnum:] | 字母和数字,即[0-9a-Za-z] |
[:alpha:] | 代表任何英文大小写字符,即[a-Za-z] |
[:lower:] | 小写字母,示例:[[:lower:]],相当于[a-z] |
[:upper:] | 大写字母,[[:upper:]]相当于[A-Z] |
[:blank:] | 空白字符(空格和制表符) |
[:space:] | 包括空格、制表符(水平和垂直)、换行符、回车符等各种类型的空白,比[:blank:]包含的范围广 |
[:cntrl:] | 不可打印的控制字符(退格、删除、警铃...) |
[:digit:] | 十进制数字 |
[:xdigit:] | 十六进制数字 |
[:graph:] | 可打印的非空白字符 |
[:print:] | 可打印字符 |
[:punct:] | 标点符号 |
\w | #匹配单词构成部分,等价于[_[:alnum:]] |
\W | #匹配非单词构成部分,等价于[^_[:alnum:]] |
\S | #匹配任何非空白字符。等价于 [^ \f\n\r\t\v] |
\s | #匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]。注意Unicode正则表达式会匹配全角空格符 |
##标注 \f:换页符,在文本编辑中,它表示一个新页的开始。 \n:换行符,在文本编辑中,它表示新的一行的开始。 \r:回车符,在文本编辑中,它表示光标移动到当前行的末尾。 \t:制表符,在文本编辑中,它表示一个制表位,通常用于对齐文本。 \v:垂直制表符,在文本编辑中,它表示一个垂直制表位,通常用于对齐文本。 |
区分正则表达式和通配符的区别
元字符 | 功能 |
* | #匹配前面的字符任意次,包括0次,贪婪模式:尽可能长的匹配 |
.* | #任意长度的任意字符,不包括0次 |
\? | #匹配其前面的字符出现0次或1次,即:可有可无 |
\+ | #匹配其前面的字符出现最少1次,即:肯定有且大于等于1次 |
\{n\} | #匹配前面的字符n次 |
\{m,n\} | #匹配前面的字符至少m次,至多n次 |
\{,n\} | #匹配前面的字符至多n次,<=n |
\{n,\} | #匹配前面的字符至少n次 |
元字符 | 功能 |
^ | #行首锚定,用于模式的最左侧 |
$ | #行尾锚定,用于模式的最右侧 |
^PATTERN$ | #用于模式匹配整行(^root$表示单独一行只有root) |
^$ | #空行,不包含空格行 |
^[[:space:]]*$ | #空白行 |
\b,\< | #词首锚定,用于单词模式的左侧(连续的数字,字母,下划线都算单词内部) |
\b,\> | #词尾锚定,用于单词模式的右侧 |
##过滤出空白行
[root@localhost /ceshi]#cat /etc/fstab |egrep -n "^[[:space:]]*$"|cat -A
grep "^[^#]" /etc/fstab ##表示非#开头的行
[root@localhost /ceshi]#echo hello-root-------shan---123 |grep "\b[a-z]*\b" -o
hello
root
shan
[root@localhost /ceshi]#echo hello-root-------shan---123 |grep "\b[[:alpha:]]*\b" -o
hello
root
shan
[root@localhost /ceshi]#
分组:( ) 将多个字符捆绑在一起,当作一个整体处理,如:(root)+
后向引用:分组括号中的模式匹配到的内容会被正则表达式引擎记录于内部的变量中,这些变量的命名
方式为: \1, \2, \3, ...
\1 表示从左侧起第一个左括号以及与之匹配右括号之间的模式所匹配到的字符
表示次数
* 匹配前面字符任意次
? 0或1次
+ 1次或多次
{n} 匹配n次
{m,n} 至少m,至多n次
{,n} #匹配前面的字符至多n次,<=n,n可以为0
{n,} #匹配前面的字符至少n次,<=n,n可以为0
表示分组
() 分组
分组:() 将多个字符捆绑在一起,当作一个整体处理,如:\(root\)+
后向引用:\1, \2, ...
| 或者
a|b #a或b
C|cat #C或cat
(C|c)at #Cat或cat
扩展练习:
1.表示qq号
[root@localhost /ceshi]#echo "1923834175" |grep "\b[0-9]\{6,12\}\b"
1923834175
2.表示邮箱
echo "[email protected]" |grep -E "[[:alnum:]_]+@[[:alnum:]_]+\.[[:alnum:]_]+"
3.表示手机号
echo "13778420927"|grep -E "\b1[3456789][0-9]{9}\b"
grep 命令的语法:grep [选项] ...查找条件 目标文件
选项:
-color=auto 对匹配到的文本着色显示
-m # 匹配#行后停止
grep -m 1 root /etc/passwd #多个匹配只取第一个
-v 显示不被pattern匹配到的行,即取反
grep -Ev '^[[:space:]]*#|^$' /etc/fstab
-i 忽略字符大小写
-n 显示匹配的行号
-c 统计匹配的行数
grep -c root /etc/passwd #统计匹配到的行数
-o 仅显示匹配到的字符串
-q 静默模式,不输出任何信息
-A # after, 后#行
grep -A3 root /etc/passwd #匹配到的行后3行业显示出来
-B # before, 前#行
-C # context, 前后各#行
-e 实现多个选项间的逻辑or关系,如:grep –e ‘cat ' -e ‘dog' file
grep -e root -e bash /etc/passwd #包含root或者包含bash 的行
grep -E root|bash /etc/passwd
-w 匹配整个单词
grep -w root /etc/passwd
useradd rooter
-E 使用ERE,相当于egrep
-F 不支持正则表达式,相当于fgrep
-f file 根据模式文件,处理两个文件相同内容 把第一个文件作为匹配条件
-r 递归目录,但不处理软链接
-R 递归目录,但处理软链接
[root@localhost /ceshi]#grep -m 2 "root" /etc/passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
[root@localhost /ceshi]#cat /etc/passwd|grep -q "\bxxxxx\b"
[root@localhost /ceshi]#echo $?
1
##表示没有这个用户
[root@localhost /ceshi]#cat /etc/passwd|grep -q "xueyin"
[root@localhost /ceshi]#echo $?
0
##表示有这个用户
##表示匹配到的内容是后3行
[root@localhost /ceshi]#cat /etc/passwd|grep "root" -A 3
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
--
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
nobody:x:99:99:Nobody:/:/sbin/nologin
[root@localhost /ceshi]#cat /etc/passwd|egrep "root|bash"
[root@localhost /ceshi]#cat /etc/passwd|grep -e "root" -e "bash"
[root@localhost /ceshi]#grep -rw "root" /etc/
##本质上是过滤的文本内容,但是前面会显示文件的路径,以及文件内匹配到的root单词高亮
##有趣统计/etc/文件夹下面有多少文件中有root单词
[root@localhost /ceshi]#grep -rw "root" /etc/|awk -F":" '{print $1}'|sort|uniq -c|wc -l
151
假设想要统计有多少个文件中含有root单词
[root@localhost /ceshi]#grep -rw "root" /etc/|awk -F: '{print $1}'|sort|uniq -c|wc -l
151
awk:Aho, Weinberger, Kernighan,报告生成器,格式化文本输出,GNU/Linux发布的AWK目前由自
由软件基金会(FSF)进行开发和维护,通常也称它为 GNU AWK
有多种版本:
AWK:原先来源于 AT & T 实验室的的AWK
NAWK:New awk,AT & T 实验室的AWK的升级版
GAWK:即GNU AWK。所有的GNU/Linux发布版都自带GAWK,它与AWK和NAWK完全兼容
GNU AWK 用户手册文档
The GNU Awk User’s Guide
gawk:模式扫描和处理语言,可以实现下面功能
vim: 是将整个文件加载到内存中 再进行编辑, 受限你的内存
awk(语言): 读取一行处理一行,
在 Linux/UNIX 系统中,awk 是一个功能强大的编辑工具,逐行读取输入文本,默认以空格或tab键作为分隔符作为分隔,并按模式或者条件执行编辑命令。而awk比较倾向于将一行分成多个字段然后进行处理。AWK信息的读入也是逐行
指定的匹配模式进行查找,对符合条件的内容进行格式化输出或者过滤处理,可以在无交互
的情况下实现相当复杂的文本操作,被广泛应用于 Shell 脚本,完成各种自动化配置任务。
###awk的工作原理
第一步:执行BEGIN{action;… }语句块中的语句
第二步:从文件或标准输入(stdin)读取一行,然后执行pattern{ action;… }语句块,它逐行扫描文件,
从第一行到最后一行重复这个过程,直到文件全部被读取完毕。
第三步:当读至输入流末尾时,执行END{action;…}语句块
BEGIN语句块在awk开始从输入流中读取行之前被执行,这是一个可选的语句块,比如变量初始化、打印输出表格的表头等语句通常可以写在BEGIN语句块中;END语句块在awk从输入流中读取完所有的行之后即被执行,比如打印所有行的分析结果这类信息汇总都是在END语句块中完成,它也是一个可选语句块pattern语句块中的通用命令是最重要的部分,也是可选的。如果没有提供pattern语句块,则默认执行{print},即打印每一个读取到的行,awk读取的每一行都会执行该语句块
##### BEGIN{}模式表示,在处理指定的文本前,需要先执行BEGIN模式中的指定动作; awk再处理指定的文本,之后再执行END模式中的指定动作,END{}语句中,一般会放入打印结果等语句。
awk为加载一行处理一行,可以接受比较大的文件处理
vim为先加载整个文件到内存中处理,若内存不够大,无法打开大文件
awk [选项] '模式{处理动作}' ##一定要用单引号
awk 'patterm{action}'
#BEGIN{}模式表示,在处理指定的文本前,需要先执行BEGIN模式中的指定动作; awk再处理指定的文本,之后再执行END模式中的指定动作,END{}语句中,一般会放入打印结果等语句。
df|awk '{print $5}'
df|awk -F"( +|%)" '{print $5}' ##一次性提取出,不要百分号
df |awk -F"[[:space:]]+|%" '{print $5}'
df |awk -F"[ %]+" '{print $5}'
cat /etc/passwd|awk -F: '{print $1,$3}'
##默认用空格分开
[root@localhost ~]#cat /etc/passwd|awk -F: '{print $1":"$3}'
#用冒号分隔开
[root@localhost ~]#cat /etc/passwd|awk -F: '{print $1"\t"$3}'
#用制表符分隔开
[root@localhost /ceshi]#hostname -I
192.168.20.6 192.168.122.1
[root@localhost /ceshi]#hostname -I|awk '{print $1}'
192.168.20.6
[root@localhost /ceshi]#ifconfig ens33|sed -n '2p' |awk '{print $2}'
192.168.20.6
[root@localhost /ceshi]#grep -c "/bin/bash$" /etc/passwd
4
[root@localhost /ceshi]#cat /etc/passwd|awk '{x++}END{print x}'
44
[root@localhost /ceshi]#cat /etc/passwd|wc -l
44
[root@localhost /ceshi]#cat /etc/passwd|awk '/bash$/{x++}END{print x}'
4
内置变量名称 | 作用 |
FS | 指定每行文本的字段分隔符,默认为空格或制表符(tab)。与“-F”作用相同 |
OFS | 输出时的分隔符 |
NF | 当前处理的行的字段个数 |
NR | 当前处理的行的行号(序数) |
$0 | 当前处理的行的整行内容 |
$n | 当前处理行的第n个字段(第n列) |
FILENAME | 被处理的文件名 |
RS | 行分隔符。awk从文件上读取资料时,将根据RS的定义就把资料切割成许多条记录,而awk一次仅读入一条记录进行处理。预设值是\n |
[root@localhost /ceshi]#awk -v "FS=:" '{print $1FS$3}' /etc/passwd
##与 -F":"
[root@localhost /ceshi]#awk -F: '{print $1":"$3}' /etc/passwd
##拓展-F -FS一起使用 -F 的优先级高
[root@localhost ~]#cat /etc/passwd|awk -v "OFS=--" -F: '{print $1,$3}'|head -n3
root--0
bin--1
daemon--2
[root@localhost ~]#cat /etc/passwd|awk -v "OFS=--" -v "FS=:" '{print $1,$3}'|head -n3
root--0
bin--1
daemon--2
[root@localhost ~]#echo $PATH|awk -v "RS=:" '{print}'
/usr/local/sbin
/usr/local/bin
/usr/sbin
/usr/bin
/root/bin
[root@localhost ~]#df |awk '{print $NF}'
##挂载点
[root@localhost ~]#df |awk '{print $(NF-1)}'
##使用百分比
[root@localhost ~]#cat /etc/passwd |head -n3|awk '{print NR,$0}'
NR也可以用与模式中使用,表示匹配对应的行
[root@localhost ~]#cat /etc/passwd |head -n3|awk '{print NR,$0}' ##打印行号
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
[root@localhost ~]#cat /etc/passwd|awk 'NR==1,NR==3{print NR,$0}' ##只打印第1行到第3行
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
[root@localhost ~]#cat /etc/passwd|awk 'NR==1||NR==3{print NR,$0}' ##只打印第1行和第3行,||表示或者
1 root:x:0:0:root:/root:/bin/bash
3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
[root@localhost ~]#cat /etc/passwd|head -n8|awk '(NR%2)==0{print NR,$0}' ##行号除2取余为0,只打印偶数行
2 bin:x:1:1:bin:/bin:/sbin/nologin
4 adm:x:3:4:adm:/var/adm:/sbin/nologin
6 sync:x:5:0:sync:/sbin:/bin/sync
8 halt:x:7:0:halt:/sbin:/sbin/halt
[root@localhost ~]#cat /etc/passwd|head -n8|awk '!(NR%2)==0{print NR,$0}' ##偶数行取反是奇数
1 root:x:0:0:root:/root:/bin/bash
3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
7 shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
[root@localhost ~]#cat /etc/passwd|head -n8|awk '(NR%2)==1{print NR,$0}' ##行号除2取余为1,只打印奇数行
1 root:x:0:0:root:/root:/bin/bash
3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
7 shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
[root@localhost ~]#cat /etc/passwd|head -n3|awk 'NR!=1{print NR,$0}' ##不打印第一行
2 bin:x:1:1:bin:/bin:/sbin/nologin
3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
[root@localhost ~]#
关于FNR的使用 :表示一次处理多个文件,但是行号不合计
awk [选项] '模式{处理动作}'
PATTERN模式:根据pattern条件,过滤匹配的行,再做处理
如果模式为空表示每一行都匹配成功,相当于没有额外条件
awk -F: '{print $1,$3}' /etc/passwd
/regular expression/:仅处理能够模式匹配到的行,需要用/ /括起来,固定搭配
awk -F: '/^root/,/^ftp/{print $1,$3}' /etc/passwd
awk -F: '/^root/||/^ftp/{print $1,$3}' /etc/passwd
不支持使用行号,但是可以使用变量NR 间接指定行号加上比较操作符 或者逻辑关系
比较操作符:
==, !=, >, >=, <, <=
#####逻辑
与:&&,并且关系 ##如NR>=3 && NR<=6 这种与NR==3,NR==6一样
或:||,或者关系 ##如NR==1||NR==3
非:!,取反 ##如NR!=1
[root@localhost ~]#awk -F: '$1=="root"||$1=="ftp"{print NR,$1,$3}' /etc/passwd
1 root 0
12 ftp 14
[root@localhost ~]#awk -F: '$NF=="/bin/bash"{print NR,$1,$3}' /etc/passwd
1 root 0
41 xueyin 1000
43 lisi 1001
44 zhangsan 1002
[root@localhost ~]#awk -F: '$3>=1000{print NR,$1,$3}' /etc/passwd
35 nfsnobody 65534
41 xueyin 1000
43 lisi 1001
44 zhangsan 1002
关系表达式结果为“真”才会被处理
真:结果为非0值,非空字符串
假:结果为空字符串或0值
补充n++的用法,实际上就是不匹配第一行 与"NR!=1"一个意思
[root@localhost ~]#ss -natp|awk 'n++{print $1}'|sort|uniq -c
1 ESTAB
12 LISTEN
[root@localhost ~]#ss -natp|awk 'n++{a[$1]++}END{for(i in a){print a[i],i}}'
12 LISTEN
1 ESTAB
[root@localhost ~]#
[root@localhost ~]#seq 4|awk 'i=!i' ##类似(NR%2)==0
1
3
[root@localhost ~]#seq 4|awk '!(i=!i)'
2
4
[root@localhost ~]#seq 4|awk -v i=1 'i=!i' ##类似(NR%2)==1
2
4
awk 选项 '模式 {actions}'
条件判断写在 actions里
if(condition){statement;…}[else statement]
if(condition1){statement1}else if(condition2){statement2}else if(condition3){statement3}...... else {statementN}
condition1:条件
statement1:语句
if语句:awk的if语句也分为单分支、双分支和多分支
单分支为if(判断条件){执行语句}
双分支为if(判断条件){执行语句}else{执行语句}
多分支为if(){}else if(){}else{}
[root@localhost ~]#cat /etc/passwd|awk -F: '{if($3>1000)print $1,$3}'
nfsnobody 65534
lisi 1001
zhangsan 1002
[root@localhost ~]#cat /etc/passwd|awk -F: '$3>1000{print $1,$3}'
nfsnobody 65534
lisi 1001
zhangsan 1002
[root@localhost ~]#cat /etc/passwd|awk -F: '{if($3>=uid){uid=$3;user=$1;sh=$NF}}END{print user,uid,sh}'
nfsnobody 65534 /sbin/nologin
for(expr1;expr2;expr3) {statement;…}
for(variable assignment;condition;iteration process) {for-body}
for(var in array) {for-body}
[root@localhost ~]#awk 'BEGIN{for(i=0;i<=100;i++){sum+=i}{print sum}}'
5050
awk数组特性:
awk的数组是关联数组(即key/value方式的hash数据结构),索引下标可为数值(甚至是负数、小数等),也可为字符串 1. 在内部,awk数组的索引全都是字符串,即使是数值索引在使用时内部也会转换成字符串 2. awk的数组元素的顺序和元素插入时的顺序很可能是不相同的
awk数组支持数组的数组
length(数组名) :统计数组下标的种类,即关联数组的长度
for(var in array) {for-body}
##注意在awk中关联数组的下标名称如果是字符串需要加双引号,赋值也需要加双引号
awk 'BEGIN{students[1]="zhaizong";students[2]="hezong";students[3]="haizong";for(x in students){print x":"students[x]}}'
[root@localhost /ceshi]#cat a.txt |awk '{a[$0]++}END{for(i in a)print i}'
[root@localhost /ceshi]#cat a.txt |awk '!a[$0]++'
将awk程序写成脚本,直接调用或执行
[root@localhost /ceshi]#cat test.txt
{if($3>=1000)print $1,$3}
[root@localhost /ceshi]#awk -F: -f test.txt /etc/passwd
nfsnobody 65534
xueyin 1000
lisi 1001
zhangsan 1002
[root@localhost /ceshi]#