文本三剑客之awk

一、简介

和 sed 命令类似,awk 命令也是逐行扫描文件(从第 1 行到最后一行),寻找含有目标文本的行,如果匹配成功,则会在该行上执行用户想要的操作;反之,则不对行做任何处理。

awk有自己的编程预言,以实现更强大的功能,例如判断、循环等。

awk基本格式如下:

awk [option] '[BEGIN{ commands }] pattern{ commands } [END{commands}]' file

其中BEGIN、pattern和END三个语句块统称为program。
commands则是awk自己的编程语言,称之为action。

awk工作原理
第一步:执行BEGIN{ commands }语句块中的语句;

第二步:从文件或标准输入(stdin)读取一行,然后执行pattern{ commands }语句块,如果pattern匹配则在此行执行commands操作。从第一行到最后一行重复这个过程,直到文件全部被读取完毕。

第三步:当读至输入流末尾时,执行END{ commands }语句块。

BEGIN语句块
在awk开始从输入流中读取行 之前 被执行,这是一个可选的语句块,比如变量初始化、打印输出表格的表头等语句通常可以写在BEGIN语句块中。

END语句块
在awk从输入流中读取完所有的行之后即被执行,比如打印所有行的分析结果这类信息汇总都是在END语句块中完成,它也是一个可选语句块。

pattern语句块
pattern是最重要的部分,它也是可选的。用于筛选要执行awk操作的行,如果没有提供pattern,则所有行执行commands。

  1. empty:空模式,匹配所有行;ACTION作用在所有行上

  2. /正则表达式/:仅将ACTION应用于能够被Regular Expression所匹配到的行;

    awk -F: '/^[ab]/{print $1,$3}' /etc/passwd  
    
  3. relational expression:关系表达式,即结果为“真”、“假”的表达式,或者其结果能类同于“真”或“假”的表达;一般来说,其结果为非0数值或非空字符串即可类同为“真”,否则,则类同为“假”;··

    awk -F: '$3>=500{print $1,$3}' /etc/passwd
    awk -F: 'NR==3{print $1,$3}' /etc/passwd 
    
  4. line ranges:行范围,通过两个正则表达式,分别确定开始的行和结束的行

    awk -F: '/^root/,/^adm/{print $1,$3}' /etc/passwd
    

注意
在pattern中可以使用awk编程语言(包括变量),上面例子中出现的>= 以及~会在后面介绍

option选项
-F fs fs指定输入分隔符,fs可以是字符串或正则表达式,如-F:
-v var=value 赋值一个用户定义变量,将外部变量传递给awk
-f scripfile 从脚本文件中读取,即将program存为scriptfile。

二、awk编程语言

2.1 awk的内置变量

FS 输入信息的字段分隔符(列),默认为空白

RS 输入信息的行分隔符,默认为换行符

OFS 输出信息的字段分隔符(列),默认为空白字符

ORS 输出信息行分隔符,默的认为换行符

NF 当前行的字段的数量

NR 记录当前是第几行,从1开始

FNR 每个文件分别计数,显示行号

FILENAME 当前文件名
变量使用举例


[root@192-168-80-114 ~]# cat /etc/resolv.conf
# Generated by NetworkManager
nameserver 223.5.5.5
[root@192-168-80-114 ~]# awk '{print NF}' /etc/resolv.conf
4
2

[root@192-168-80-114 ~]# awk 'BEGIN{OFS=":"}{print FILENAME,FNR}' /etc/resolv.conf /etc/fstab 
/etc/resolv.conf:1
/etc/resolv.conf:2
/etc/fstab:1
/etc/fstab:2
/etc/fstab:3
/etc/fstab:4
/etc/fstab:5

2.2 awk的内置函数

2.3 awk的操作符

算术操作符
如:A+B A-B A*B A/B

[root@192-168-80-114 ~]# awk -v f1=5 -v f2=2 'BEGIN{f3=f1+f2;print f3}' 
7

字符操作符

赋值操作符
如:= += /= %= *=

[root@192-168-80-114 ~]# awk -v f1=5 'BEGIN{f1*=5;print f1}'
25

比较操作符
如:> >= < <=

awk -F: '$3>=500{print $1,$3}' /etc/passwd

逻辑操作符
&& 与运算 || 或运算

模式匹配操作符
~ 是否能被右侧指定的模式所匹配;
!~ 是否不能被右侧指定的模式所匹配

条件表达式
selector?if-true-expression:if-ials-expreion

[root@192-168-80-114 ~]# awk -F":" '{$3>=1000?usertype="com_user":usertype="sys_user";print $1,usertype}' /etc/passwd
root sys_user
bin sys_user
rpcuser sys_user
nfsnobody com_user

函数调用
调用函数来进行数据的处理

2.4 awk的流程控制

if-else
语法:
if (condition) statement [ else statement ]
if (condition) {statements} [else {statements}]

使用场景:对awk取得的整行或行中的字段做条件判断;

awk -F: '{if ($3>=500) print $1,$3}' /etc/passwd
#打印出用户ID大于500(即普通用户)的用户名以及用户ID
awk '{if (NF>=6) print NF,$0}' /etc/rc.d/rc.sysinit
#打印出字段数大于6的整行,以及其中的最后个字段
awk -F: '{if ($3>=500) {print $1,"is a common user"} else {print $1,"is a sysadmin or sysuser"}}' /etc/passwd
#判定每行如果用户ID大于500则打印用户名并指出是普通用户,否则打印用户名并指出为系统用户

while循环
语法:
while (condition) statement
while (condition) {statements}

使用场景:通常用于在当前行的各字段间进行循环;

awk '{i=1;while(i<=NF){if (length($i)>=6) {print $i};i++}}' /etc/issue
#打印每行中字段长度大于等于6的打印出来

do-while循环
语法:do statement while (condition)
do {statements} while (condtion)

awk 'BEGIN{i=1;do {print "test"; i++} while (i<1)}'

意义:至少执行一次循环体

for循环
语法:for (expr1;expr2;expr3) statement
for (expr1;expr2;expr3) {statements}

awk '{for(i=1;i<=NF;i++){if(length($i)>=6) print $i}}' /etc/issue

swtich
语法:switch (expression) {case VALUE or /REGEXP/: statement; …; default: statementN}

break and continue
break [n]:退出当前循环,n是一个数字,用于指定退出几层循环;
continue:提前结束本轮循环而进入下一轮;

next
提前结束对本行文本的处理,而提前进入下一行的处理操作;

awk -F: '{if($3%2==0) next;print $1,$3}' /etc/passwd
#打印用户ID为奇数的行中第一字段和第三字段

2.4 awk的数组

数组类似于其他语言中字典,表现形式:weekdays[mon]=“Monday”。

如果某数组元素事先不存在,则在引用时,awk会自动创建此元素并将其值初始化为空串;

如果需要遍历数组,使用for (i in weekdays)

举例使用:

#整个文件统一统计:~]
awk '{for(i=1;i<=NF;i++) {count[$i]++}}END{for(j in count) {print j,count[j]}}' /root/count.txt	
				
#每行单独统计:
awk '{for(i=1;i<=NF;i++) {count[$i]++};for(j in count) {print j,count[j]};delete count}' /root/count.txt

#练习:统计当前系统上所有tcp连接的各种状态的个数;
ss -tan | awk '!/^State/{state[$1]++}END{for(i in state) print i,state[i]}'

#练习:统计指定的web访问日志中各ip的资源访问次数:
awk '{ip[$1]++}END{for(i in ip) print i,ip[i]}'	/var/log/httpd/access_log

2.5 格式化输出

awk的输出命令之一:print

用法:print item1, item2, …
item:只存在以下三种类型
字符串
用引号引用,打印字符串;

#print "hello","world"  只显示双引号内的字符串
awk '{print "hello","world" }' /tmp/fstab 
#awk依据/tmp/fstab逐行执行'{print "hello","world" }';其中两个单词间逗号表示打印输出时使用字符串分隔符(默认是空格)隔开。 

变量
引用变量:直接使用变量名,便会输出变量的值

awk 'BEGIN{f1=2;print f1}' 

如果实现使用-v 为变量赋值数字,且在引用时加了$则会出现下列情况

数值
无须加引号,直接输出数字

 intem中出现$2数值等是表现第2片段的内容,$0代表引用awk正读取行的整行内容。

要点:

  1. 各item之间需要使用逗号分隔;而输出时的分隔符为默认为空白字符;
  2. 输出的各item可以为字符串或数值、当前记录的字段($#例如:$2)、变量或awk的表达式;数值会被隐式转换为字符串进行输出;
  3. print后面的item省略时,相当于运行“print $0”,用于输出整行;
  4. 输出空白字符:print " "

2、awk的输出命令之二:printf

用法:printf FORMAT,item1,item2,…
要点:
(1) 必须提供FORMAT;
(2) 与print语句打印输出时不同,printf打印输出不会自动换行,需要显式指定换行符:\n
(3) FORMAT中需要分别为后面的每个item指定一个格式符,否则item则无法显示;

格式符:都以%开头,后跟单个字符;

  • %c: 显示字符的ASCII码;

  • %d, %i:显示为十进制整数;

  • %e, %E: 科学计数法显示数值;

  • %f:显示为浮点数;

  • %g, %G:以科学计数法或浮点数格式显示数值;

  • %s: 显示为字符串;

  • %u:显示无符号整数;

  • %%: 显示%符号自身;

    格式符依次对应后面出现的item1 item2…

修饰符:用以修正格式符已达到特殊的格式要求

  • #[.#]:([]表示精度有时可以忽略不写)
    左边的#:用于指定显示对应item时的宽度; 右边的#: 显示精度;
  • +:显示数值符号
  • -:左对齐(如果宽带大于item本来的宽度,默认是向右靠起)
#输出时字段的分隔符由printf中的格式决定
awk -F: '{printf "%20s:%-20d\n",$1,$3}' /etc/passwd
                root:0                   
                 bin:1                   
              daemon:2                   
                 adm:3                   
                  lp:4                   
                sync:5                   
            shutdown:6                   
                halt:7                   
                mail:8                   
            operator:11       
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值