Linux:shell脚本:基础使用(6)《正则表达式-awk工具》_awk 分隔符 正则表达式ops_request_misc=%257B%2522request%255Fid%2522%253A%2522170842394816800185872161%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=170842394816800185872161&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_ecpm_v1~rank_v31_ecpm-1-132406372-null-null.nonecase&utm_term=awk&spm=1018.2226.3001.4450awk的基础文章
1.awk的作用:一种编程语言,用于在linux/unix下对文本和数据进行处理。数据可以来自标准输入stdin、一个或多个文件,或其它命令的输出。简单来说awk就是把文件逐行的读入,以空格为默认分隔符将每行切片,切开的部分再进行各种分析处理。擅长取行、取列、过滤。
2.语法:
awk [选项] '模式{ 动作(action) }' 文件1 文件2 ...
选项: -F 指定输入分隔符,可以是字符串或正则表达式;
最常见的动作: print、printf
切片筛选案例
chkconfig --list |grep 3:启用 |awk '{print $1}'
#找出再init3 下开机自启的服务名
tail -1 /etc/passwd |awk -F ':' 'BEGIN{OFS="---"}{print $1,$6,$7}'
#OFS指定输出分隔符
ifconfig ens33 |awk -F '[ :]+' 'NR==2 {print $3}'
#找出ip地址
ifconfig ens33 |awk -F '[ :]+' 'NR==2 {print "ens_ip="$3}'
#查询ip,提示出ens_ip= “ip地址”
awk 'BEGIN {print "line one \nline two\nline three"}'
#line one
#line two
#line three
awk -F':' 'BEGIN {print "line one \nline two\nline three",OFS="----------"}''{print $1,$2}''END {print "line one \nline two\nline three"}' /etc/passwd
#这个你输出一下就知道了
匹配范围
注解:
$1=="" ##精确匹配等于
$1!="" ##精确匹配不等于
$1~"" ##包含匹配等于
$1!~"" ##包含匹配不等于
awk -F : '$3==3,$3==10{print $1,$3,$7}' /etc/passwd
awk -F : '$1=="root",$1=="adm"{print $1,$3,$7}' /etc/passwd
awk -F : '/^r/,/^a/{print $1,$3,$7}' /etc/passwd
awk -F ':' '($7!~"/sbin"){print $1,$7}' /etc/passwd
##查找$7不包含/sbin作为条件,进行打印
awk -F ':' '($7!="/bin/bash")&&($7!="/sbin/nologin"){print $1}' /etc/passwd
##查找$7不等于/bin/bash并且$7不等于/sbin/nologin作为条件,进行打印
awk -F ':' '($5~"99999")&&($2=="*"){print $1,$5}' /etc/shadow
##查找$5包含99999并且$2等于*作为条件,进行打印;
awk区块原理
BEGIN { 动作 } #开始处理第一行文本之前的操作
{ 动作 } #针对每一行文本的处理操作
END { 动作 } #处理完最后一行文本之后的操作
执行流程:
首先执行 BEGIN { } 区块中的初始化操作;
然后从指定的数据文件中循环读取一个数据行(自动更新 NF、 NR、 $0、 $1…… 等内建变量的值),并执行'模式或条件{ 动作 }';
最后执行 END { } 区块中的后续处理操作。
awk -F : 'BEGIN{printf "%-20s%-20s%-20s\n","UserName","ID","Shell"}{printf "%-20s%-20s%-20s\n",$1,$3,$7}' /etc/passwd
ifconfig ens33 |awk 'NR==2{print $2,$4}'|awk 'BEGIN{OFS=" / "}{print "IP="$1,"MASK="$2}'
awk的变量
FS:列分隔符,默认位空白
RS:行分隔符,默认位换行符
OFS:输出列分隔符
ORS :输出行分隔符
awk内置变量:
NR:处理中行数
FNR:单个文件的行数
NF:列的个数
awk 'BEGIN{print test="123" $test}'
awk -v test="123" 'BEGIN{print test}'
两种定义变量的方法
printf的使用
格式:printf "格式",列表1,列表2 ...
特征:
a.必须指定format(格式),用于指定后面item(列表)的输出格式
b.printf语句不会自动打印换行符:\n
c.format格式以%加一个字符,如下:
%c:显示字符的ASCII码
%d,%i:十进制整数
%f:显示浮点数(小数)
%s:显示字符串
%u:无符号整数
%%:显示%
d.修饰符:N:显示宽度,-:左对齐,+:显示数值符号,如%-c(左对齐)
chkconfig --list |grep 3:开 |awk '{printf "%-10s\n",$1}'
awk -F : '{printf "%-15s %-10d %-10s\n",$1,$3,$7}' /etc/passwd
awk的操作符:
算数操作符: x^y、x/y、x+y、x-y、x%y
比较操作符:>、<、>=、<=、==、!=
逻辑操作符:&&、||、!
awk常见的模式类型
正则表达式(regexp):awk -F : '/^u/{print $1}' /etc/passwd
表达式(expression):值位非0或位非空是满足条件,如$1 ~ /foo/或 $1 == "root"
awk -F : '$3>=500{print $1,$3,$7}' /etc/passwd ##打印普通用户
awk -F : '$3+1<=100&&$3+1>=10{print $1,$3,$7}' /etc/passwd ##UID在10-100之间的用户
awk -F : '$2=="!!"{print $1,$2}' /etc/shadow ##检查未初始化密码的用户
passwd -d u01
awk -F : '$2==""{print $1}' /etc/shadow ##打印密码为空的用户
awk -F : '$7~"bash$"{print $1,$3,$7}' /etc/passwd ##匹配$7为bash结束行
awk -F : '$7!~"bash$"{print $1,$3,$7}' /etc/passwd
if-else:判断
语法:if (条件表达式) 命令 操作1; else 命令 操作2
案例:
awk -F : '$7~"bash"{if ($1=="root") print $1, "admin";else print $1, "Common User"}' /etc/passwd ##第七列是bash,如果第一列是root打印root admin,否则打印出第一列 common user
awk -F : -v sum=0 '{if ($3>=500) sum++}END{print sum}' /etc/passwd ##输出普通用户的数量
awk -F : '$7~"bash$"{if ($1=="root") printf "%-15s: %s\n",$1,"admin";else printf "%-15s: %s\n",$1,"common user"}' /etc/passwd ##使用printf打印
while循环:
循环字段(列),awk本身就是行的循环
语法:while (条件){语句1;语句2;...}
案例:
awk -F: '{i=1;while (i<=3) {print $i;i++}}' /etc/passwd ##循环打印前3列
awk -F : '{i=1;while (i<NF) {if (length($i)<=4) print $i;i++}}' /etc/passwd ##循环整行,并打印出长度小于4的字段列
for:循环
语法:for (初始变量;条件;变量自加){语句1, 语句2,...}
案例:
awk -F : '{for(i=1;i<=3;i++) print $i}' /etc/passwd
数组
语法:数组名[下标]
解释:awk中数组(array)的下标(index-expression)可以使用任意字符串;需要注意的是,如果某数据组元素事先不存在,那么在引用其时,awk会自动创建此元素并初始化为空串;因此,要判断某数据组中是否存在某元素,需要使用“下标 in 数组”的方式。要遍历数组中的每一个元素,需要使用如下的特殊结构:for (变量 in 数组) { 语句1, ... }
案例:
[root@localhost ~]# netstat -ant
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN
tcp 0 0 127.0.0.1:25 0.0.0.0:* LISTEN
tcp 0 0 192.168.1.106:22 192.168.1.101:36318 ESTABLISHED
以上命令显示的结果中,每一行最后一个字段为状态,若要统计每种状态的个数,只需要将state作为数组下标,由于awk本身就是一个行的循环,所以只需要给数字自加1(++)即可实现统计,具体操作如下:
[root@localhost ~]# netstat -ant |awk '/^tcp|^udp/{state[$6]++}END{for(i in state){print i,state[i]}}' ##state[$6]++表示定义数组state[]、$6是下标,++表示自加1
[root@localhost ~]# netstat -ant |awk '/^tcp/{S[$NF]++}END{for(a in S) print a, S[a]}'
[root@localhost ~]# awk '{counts[$1]++}END{for (url in counts) print url,"access times:",counts[url]}' /var/log/httpd/access_log ##查看http的访问
[root@localhost ~]# awk '{AH[$1]++}END{for (i in AH) printf "%-20s:%s\n", i, AH[i]}' /var/log/httpd/access_log