shell文本处理三剑客之awk详解

文本处理:awk

语法:
awk  [选项]   '命令'    文件
awk   [options]   'commands'      filenames (推荐)

命令:
 BEGIN 行处理之前(注意大写)
	{ } 	行处理时
	END 	行出来之后
	\n 		回车符
	\t		空格
内部变量:

FS:输入字段分隔符(默认空格)

[root@localhost ~]# awk -F: '{print $1, $3}' /etc/passwd | head -1
root 0[root@localhost ~]# awk -F'[ :\t]' '{print $1,$2,$3}' /etc/passwd | head -1
root x 0[root@localhost ~]# awk 'BEGIN{FS=":"} {print $1,$3}' /etc/passwd | head -1
root 0

OFS:输出字段分隔符

[root@localhost ~]# awk -F: '{print $1,$2,$3,$4}' /etc/passwd | head -1
root x 0 0

[root@localhost ~]# awk -F: 'BEGIN{FS=":";OFS="+++"}{print $1,$2,$3,$4}' /etc/passwd | head -1
root+++x+++0+++0

RS:输入记录(行)分隔符,默认换行符

[root@localhost ~]# awk   '{print $0}' a.txt 
111 222 333 444 555:666:777
[root@localhost ~]# awk 'BEGIN{RS="   "}{print $0}' a.txt 
111
222
333
444
555:666:777
请注意,在此时记录已经不是行的概念了。分隔符由”换行符“换成了”空格“

[root@localhost ~]# awk 'BEGIN{RS=" ";ORS="+++"}{print $0}' a.txt 
111+++222+++333+++444+++555:666:777
输出记录分隔符换成了“+++”。如果不指定输出记录分隔符会如何呢?

ORS:输出记录(行)分隔符,默认换行符
FNR:多文件独立编号
NR多文件汇总编号

[root@localhost ~]# awk -F: '{print NR, $0}' /etc/centos-release /etc/hosts
1 CentOS Linux release 7.3.1611 (Core) 
2 127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
3 ::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
[root@localhost ~]# awk -F: '{print FNR, $0}' /etc/centos-release /etc/hosts
1 CentOS Linux release 7.3.1611 (Core) 
1 127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
2 ::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
字段总数
[root@localhost ~]# awk -F: '{print NF, $0}'  /etc/passwd
7 root:x:0:0:root:/root:/bin/bash
7 bin:x:1:1:bin:/bin:/sbin/nologin
7 daemon:x:2:2:daemon:/sbin:/sbin/nologin

[root@localhost ~]# awk -F: '{print NF, $NF}'  /etc/passwd
7 /bin/bash
7 /sbin/nologin
7 /sbin/nologin
格式化输出:

print 函数

[root@localhost ~]# date |awk '{print "Month: " $2 "\nYear: " $1}'
Month: 11月
Year: 2017年
\n换行符
想输出文字,用引号
[root@localhost ~]# awk -F: '{print "username is: " $1 "\t uid is: " $3}' /etc/passwd | head -1
username is: root	 uid is: 0
root@localhost ~]# awk -F: '{print "\tusername and uid: " $1,$3 "!"}' /etc/passwd  | head -1
username and uid: root 0!

printf 函数
语法:

		%s 字符类型
		%d 数值类型
		%f 浮点型,可以定义保留
			占15字符
		- 表示左对齐,默认是右对齐
		printf默认不会在行尾自动换行,加\n
		, 逗号,输出字段分隔符
示例
[root@localhost ~]# awk -F: '{printf "%-10s %-10s %-15s\n", $1,$2,$3}' /etc/passwd | head 
[root@localhost ~]# awk -F: '{printf "|%-15s| %-10s| %-15s|\n", $1,$2,$3}' /etc/passwd | head
[root@localhost ~]# awk -F: '{printf "|%-15s| %-15s| %0.1f|\n", $1,$2,$3}' /etc/passwd | head
[root@lwq ~]# head -3 /etc/passwd |awk -F":" '{printf "%-10s %-10s %-10s\n",$1,$2,$3}'
{-是向左对齐   %10s是每段占10个字符  \每行结束输出一个回车}
root           x          0         
bin            x          1         
daemon         x          2         
模式(正则表达)和动作

模式:可以是条件测试,正则,复合语句
动作:可以是打印,计算等。
概念:

任何awk语句都由模式和动作组成。模式部分决定动作语句何时触发及触发事件。
如果省略模式部分,动作将时刻保持执行状态。每一行都会有动作。
模式可以是任何条件语句或复合语句或正则表达式。有模式的话,就是对模式对应的行进行动作。

字符串比较
awk    '/^root/'/etc/passwd    			#/^root/ (root开头的)
awk '$0 ~ /^root/' /etc/passwd			#~像是以root开头 模糊查询
awk '$0!~/^root/' /etc/passwd			#!取反
awk -F: '$1 ~ /^root/' /etc/passwd     #第一列以root开头的行
数值比较:

比较表达式采用对文本进行比较,只有当条件为真,才执行指定的动作。比较表达式使用关系运算符,
用于比较数字与字符串。

关系运算符:

运算符 		含义 			示例
< 			小于 			x<y
<= 			小于或等于 		x<=y
== 			等于		 		x==y
!=		 	不等于			x!=y
>= 			大于等于 		x>=y
> 			大于 			x>y

示例:

awk -F: '$3 == 0' /etc/passwd 		第三列等于0
awk -F: '$3 == 1' /etc/passwd 		第三列等于1
awk -F: '$3 < 10' /etc/passwd		第三列小于10
== 也可以用于字符串判断
awk -F: '$7 == "/bin/bash"' /etc/passwd		第七列等于/bin/bash
awk -F: '$1 == "alice"' /etc/passwd			第一列等于alice

算术 运算

语法
	+ - * / %() ^(幂2^3) 
示例
	awk -F: '$3 * 10 > 500' /etc/passwd
多条件:
逻辑操作符和复合模式

&&:并且 ||或者

awk -F: '$1~/root/ && $3<=15'	 	/etc/passwd
awk -F:	 '$1~/root/ || $3<=15'		/etc/passwd
awk -F:	 '!($1~/root/ || $3<=15)' 	/etc/passwd	
范围模式:

语法:

awk '/从哪里/,/到哪里/' filename

示例:

awk -F: '/adm/,/lpd/' /etc/passwd	从adm到ldp,显示出来,注意避免匹配重复的字段。
awk脚本编程:
变量
awk调用变量
	自定义内部变量 -v
	awk -v user=root -F: '$1 == user' /etc/passwd
	-v定义变量
外部变量 “ ‘ ”
	双引号
	var="bash"
	echo "unix script" | awk "{print "123",\"$var\"}"
	123 bash
注意 awk调用外部变量时,外部使用双引号,内部也使用双引号,但需要转义内部的双引号
	单引号
	var="bash"
	echo "unix script" |awk '{print $1,"'"$var"'"}'
	unix  bash
注意使用单引号时,内部需要用双引转义
条件&判断

if语句:

	格式
		{if(表达式){语句;语句;...}
	示例
		需求
			如果$3是0,就说他是管理员
		awk -F: '{if($3==0) {print $1 " is administrator."}}' /etc/passwd
		需求
			统计系统用户数
		awk -F: '{if($3>0 && $3<1000){count++;}} END{print count}' /etc/passwd 

if…else语句:

格式
			{if(表达式){语句;语句;...else{语句;语句;...}}
	{if(){}else{}}
		示例
			需求
				如果第三列是0,打印该行第一列,否则打印第七列,登录shell
			示例
				awk -F: '{if($3==0){print $1} else {print $7}}' /etc/passwd
			需求
				统计管理员和系统用户数量
			示例
				awk -F: '{if($3==0){count++} else{i++}} END{print "管理员个数: "count ; print "系统用户数: "i}' /etc/passwd

if…else if…else语句:

格式
	{if(表达式1){语句;语句;...else if(表达式2){语句;语句;...else if(表达式3){语句;语句;...else{语句;语句;...}
	if (条件){动作}elseif(条件){动作}else{动作}
	if(){}else if  (){}else if(){}else{}
示例

需求:
显示出三种用户的信息
管理员:管理员ID为0
内置用户:用户ID<1000
普通用户: 用户ID>999

示范:

[root@localhost ~]$ awk -F:  '{if($3==0){print $1," is admin "}else if ($3>999){print $1," is user"}else {print $1, " is sofo user"}}'  /etc/passwd
root  is admin 
bin  is sofo user
daemon  is sofo user
adm  is sofo user
lp  is sofo user
sync  is sofo user
shutdown  is sofo user
halt  is sofo user
mail  is sofo user
operator  is sofo user
games  is sofo user
ftp  is sofo user
nobody  is sofo user
systemd-network  is sofo user
dbus  is sofo user
polkitd  is sofo user
tss  is sofo user
postfix  is sofo user
chrony  is sofo user
sshd  is sofo user
aofa  is user
apache  is sofo user
示例

题目:
统计出三种用户的数量
管理员数量:管理员ID为0
内置用户数量:用户ID<1000
普通用户数量: 用户ID>999

awk -F: '{if($3==0){i++} else if($3>999){k++} else{j++}} END{print i; print k; print j}' /etc/passwd

升级

awk -F: '{if($3==0){i++} else if($3>999){k++} else{j++}} END{print "管理员个数: "i; print "普通用个数: "k; print "系统用户: "j}' /etc/passwd
循环
while
循环打印10个数字
awk 'BEGIN{  while(i<=10){print i; i++} }'
示范
[root@localhost ~]# awk 'BEGIN{ i=1; while(i<=10){print i; i++} }' 
1
2
3
4
5
6
7
8
9
10
第一行打印十次
awk -F: '{ while(i<=9) {print $0; i++}}'  passwd
for
循环打印5个数字
awk 'BEGIN{for(i=1;i<=5;i++){print i} }'
不适用BEGIN可以吗?
{},END{}可以吗?可以需要有文件。
将每行打印10次
awk -F: '{ for(i=1;i<=10;i++) {print $0} }' /etc/passwd
打印每一行的每一列
awk -F: '{ for(i=1;i<=NF;i++) {print $i} }' passwd
说明:NF是最大列数,循环打印了每一列。
awk -F: '{ for(i=1;i<=NF;i++) {print $i} }' passwd
root
x
0
0
root
/root
/bin/bash
数组
定义数组
需求
将用户名定义为数组的值,打印第一个值
awk -F: '{username[++i]=$1} END{print username[1]}' /etc/passwd
root
数组遍历
按索引遍历
[root@localhost ~]$ awk -F: '{username[x++]=$1} END{for(i in username) {print i,username[i]} }' /etc/passwd
10 games
11 ftp
12 nobody
13 systemd-bus-proxy
14 systemd-network
15 dbus
16 polkitd
30 chrony
17 abrt
31 ntp
18 unbound

awk编程案例

1. 统计/etc/passwd中各种类型shell的数量

 awk -F: '{shells[$NF]++} END{ for(i in shells){print i,shells[i]} }' /etc/passwd
提示
$NF 最后一列的字段内容
{}行处理
把统计的对象,作为索引。每次递增。
Print i  打印索引
Shells[i]  数组加索引,显示的就是值。

2. 统计Apache/Nginx日志中的访问前十 <统计日志>

cat  access_log |awk '{ips[$1]++} END{for(i in ips){print i,ips[i]} }' |sort -k2 -rn |head
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值