AWK学习

本文详细介绍了awk的调用方式,包括命令行、脚本和shell脚本插入。讲解了模式与动作、基本用法,如域标识、条件控制语句、循环控制语句、运算、数组、内置变量和函数。同时,给出了多个awk实战例子,如文件去重、内容合并和查找差异记录。
摘要由CSDN通过智能技术生成

博客搬家,原地址:https://langzi989.github.io/2018/09/12/awk%E5%AD%A6%E4%B9%A0/

AWK是一种强大的文本处理工具,其处理文本的效率极高,其输出可以来自标注输入、其他命令的输出或一个或多个文件,熟练使用awk将会对工作效率有很大的提升。

awk调用方式

awk调用方式包括三种:

一、命令行调用
awk [-F seperator] 'commond' input-file

commond的组成又可以包括多个模式和动作的组合,即命令行调用又可以写为:

akw [-F seperator] 'parrtern1 {Action1} pattern2 {Action2}' input-file
  • seperator:分隔符。分隔符为可选参数,可以为任意字符串,若不指定,默认分隔符为空格。
  • commond:awk命令
  • input_file: 待处理的文本文件
二、脚本调用
awk -f awk-script-file input-file

将awk命令写入一个文件中,然后使用-f参数指定该文件运行

三、shell脚本插入awk命令

在shell中插入awk命令对文件进行处理,直接执行shell命令。

模式与动作

任何awk语句都由**模式**和**动作**组成,**模式部分决定Action语句何时触发以及触发事件,动作决定对当前被匹配的数据进行的操作**,Action中由多个awk处理语句组成。
awk [-F seperator] 'parrtern1 {Action1} pattern2 {Action2}' input-file

注意问题

  • awk语句必须被单引号或双引号包含,防止awk语句被当做shell命令解析。

  • 确保awk命令中所有引号都成对出现

  • 确保用花括号括起来动作语句,用圆括号括起来条件语句

  • 模式与动作一一对应,只有pattern匹配成功,对应的action(用{}括起来表示一个action)才会执行。

  • 模式可以为任何条件语句复合语句正则表达式,也可以为awk保留字BEGIN,END

  • 模式尽量不要加双引号,否则某些情况下可能会失效,如"$1>30"。

  • action一定要用{}括起来,一个{}括起来的动作属于一个action,不同{}括起来的动作属于不同action,其对应不同的pattern。

  • BEGIN和END为特殊的模式,BEGIN模式使用在任何文本浏览之前,常用来做一些初始化设置或打印头部信息等,END模式使用在完成文本浏览动作之后,常用来处理一些收尾打印等工作。注意BEGIN和END语句都仅且执行一次

awk基本用法

假定一下为一个学校中抽样的几个学生的成绩(score.txt),下面四列分别为学号,名字,年级,分数:

13331264 tom   grade4 94
13342010 marry grade4 90
13315012 jemmy grade1 85
13323089 jane  grade2 80
域标识
awk从输入文件中**每次读取一行**,当遇到分割符时将其分割为域,这些域被标记为\$1,\$2,\$3...,直到读到文件结尾或文件不存在,$0表示当前记录(即当前行)。

示例:

# 不加pattern
awk '{print $1,$4}' score.txt

输出结果:
13331264 94
13342010 90
13315012 85
13323089 80

# pattern为$4>=90,过滤分数超过90分的用户才处理
awk '$4>=90 {print $1,$4}' score.txt
输出结果:
13331264 94
13342010 90

# 命令有两个parttern action组,第一个pattern为BEGIN,第二个patter为$4>=90
awk 'BEGIN {print "学号     成绩"} $4>=90 {print $1,$4}' score.txt
输出结果:
学号     成绩
13331264 94
13342010 90
条件控制语句

关系与正则运算符

符号描述
<小于
<=小于等于
>大于
>=大于等于
==等于
~匹配正则表达式(二元 符号前面为被匹配的字符串,后面为模式串,一般模式传用/pattern/括起来)
!~不匹配正则表达式

逻辑运算符

逻辑运算符与C语言中完全一致。

符号描述
&&且,两个条件同时满足才为真
||或,只要有一个条件为真即为真
!将结果取反(一元运算符)

关键字

关键字描述
break用于while或for循环,退出循环
continue终止当前循环,执行下一个循环
next导致读入下一个输入行,并返回到脚本的顶部。这可以避免对当前输入行执行其他的操作过程。
exit退出执行,直接跳转到END执行,若没有END,终止脚本

if条件控制语句

在awk中使用if判断条件时,必须将if后面的条件用()括起来,与C语言类似。
# 过滤学号中有1333字符串的成绩记录
awk '{if($1~/1333/) print $0}' score.txt
输出:
13331264 tom   grade4 94

# 过滤学号中不含1333字符串的成绩记录
awk '{if($1!~/1333/) print $0}' score.txt
输出:
13342010 marry grade4 90
13315012 jemmy grade1 85
13323089 jane  grade2 80


# 过滤成绩大于85分的成绩记录
awk '{if($4>85) print $0}' score.txt
输出:
13331264 tom   grade4 94
13342010 marry grade4 90

# 过滤成绩大于90小于100的成绩记录
awk '{if($4>90&&$4<100) print $0}' score.txt
输出:
13331264 tom   grade4 94

当然我们使用模式代替if条件判断,这个可以达到相同的效果

# 使用条件语句
awk '{if($4>85) print $0}' score.txt

# 使用模式过滤行
awk '$4>85 {print $0}' score.txt  
for循环控制语句

语法

# 格式一:
for (变量 in 数组)
{
    do_something;
}

# 格式二(与C语言相同)
for (变量;条件;表达式)
{
    do_something;
}

使用示例

# ENVIRON为awk内置的环境变量,下面会说到。其为一个数组,该作用为打印环境变量中的所有键值对
awk 'BEGIN {for(k in ENVIRON) {print k"="ENVIRON[k];}}'

# 打印0-9
awk 'BEGIN {for(i=0;i<10;i++) {print i}}'
while循环控制语句

语法:

while (条件表达式)
{
    do_something;
}

使用示例

# 打印0-9
awk 'BEGIN {i=0; while (i<10){print i;i++}}'
do while循环控制语句

语法:

do
{
    do_something
}
while (条件表达式)

使用示例

#打印0-9
awk 'BEGIN {i=0;do{print i; i++;} while (i<10)}'
awk运算

算术运算符

符号描述
+ - * / %加/减/乘/除/取余
++自增1
自减1
+一元加操作符,将操作数乘以1
-一元减操作符,将操作数乘以-1
^求幂。如2^2=4

赋值运算符

符号描述
=赋值
+=、-=、*=、/=、%=、^=将左右操作数进行对应操作,然后赋值给左操作数(与C语言完全一致)

其他运算符

符号描述
$字段引用(引用域)
? :条件表达式(与C语言一致)
空格字符串连接符
in判断数组中是否存在某个键值

运算符优先级:
在这里插入图片描述

awk数组
awk数组是一种关联数组,其下标既可以是数字,也可以是字符串。
  • 无需定义,数组在使用时被定义
  • 数组元素的初始值为0或者空字符串
  • 数组可以自动扩展

使用示例:

# 数组可直接使用,且无需定义
awk 'BEGIN {a["123"]=2;print a["123"]}'
输出:
2

# 可使用for循环对数组中的元素进行循环读取
awk 'BEGIN {a[1]=2;a[2]=3;a[3]=4; for(k in a) print k"="a[k];}'
输出:
1=2
2=3
3=4

# 可以通过if 判断某个key是否在数组中
awk 'BEGIN {a[1]=2;a[2]=3;a[3]=4; print 5 in a; print 1 in a}'
输出:
0
1

# 删除数组中的元素,使用delete arr['key']
awk 'BEGIN {a[1]=2;a[2]=3;a[3]=4; delete a[1];for(k in a) print k"="a[k];}'
输出:
2=3
3=4

# 多维数组的下标分隔符默认为“\034”,可通过设定SUBSEP修改多为数组的下标分隔符
awk 'BEGIN {a[1,2]=10; for(k in a) print k"="a[k];}'
输出:
12=10

awk 'BEGIN {SUBSEP=":";a[1,2]=10; for(k in a) print k"="a[k];}'
输出:
1:2=10
awk内置变量
变量描述
ARGC命令行参数个数,awk后参数个数
ARGV命令行参数数组,数组下标从0开始
ENVIRON系统环境变量数组
FILENAME输入文件的名字
FNR浏览文件的记录数(文件中的记录数,若多个文件不会累加)
NR已读记录数(已读的记录数,若多文件会离家)
NF浏览记录域的个数(即每行分割的域的最大值)
FS设置域分割符,常用于BEGIN中设置域分割符
RS设置记录分隔符,原记录分隔符默认为换行,即一行一行读取,可使用该参数控制其不按照行读取
OFS设置输出域分隔符,原域默认分隔符为空格,可使用此分隔符修改
ORS设置输出记录分隔符。原记录默认分隔符为换行,可使用此参数修改

使用示例:

# ARGC测试
awk 'BEGIN {print ARGC}' score.txt
输出:
2

# ARGV测试
awk 'BEGIN {print ARGC; print ARGV[0];print ARGV[1]}' score.txt
输出:
2
awk
score.txt

# ENVIRON测试
awk 'BEGIN {for(k in ENVIRON) {print k"="ENVIRON[k];}}'

# FILENAME测试
 awk 'BEGIN {i=0} {if(i==0){print FILENAME;i++}}' score.txt
输出:
score.txt

# FNR测试
awk ' END {print FNR}' score.txt
输出:
1
2
3
4

#NR 测试
awk '{print NR}' score.txt  
输出:
1
2
3
4

# NF测试
awk ' END {print NF}' score.txt

# FS测试(以下两种方式效果一致)
awk 'BEGIN {FS="\t"} {print NR}' score.txt
awk -F'\t' '{print NR}' score.txt

# OFS测试
awk 'BEGIN {OFS="|"} {print $1,$2}' score.txt
输出:
13331264|tom
13342010|marry
13315012|jemmy
13323089|jane

# ORS测试
awk 'BEGIN {ORS="|"} {print $1,$2}' score.txt
输出:
13331264 tom|13342010 marry|13315012 jemmy|13323089 jane|

# RS测试
awk 'BEGIN {RS="1333"} {print $1,$2}' score.txt
输出:

1264 tom

FNR与NR区别

cat a.txt
111
222
111
333
444
cat b.txt
111
555
666

awk '{print FNR}' a.txt b.txt
1
2
3
4
5
1
2
3

awk '{print NR}' a.txt b.txt
1
2
3
4
5
6
7
8
awk内置函数

计算相关函数:

函数描述
cos(expr)计算余弦值,参数为弧度
sin(expr)计算正弦值,参数为弧度
int(expr)取整
log(expr)计算expr的自然对数
sqrt(expr)计算expr的平方根
# 测试cos
awk 'BEGIN {print cos(60*3.1415936/180)}'
输出:
0.5

# 测试int
awk 'BEGIN {print int(20.5)}'
输出:
20
# 测试log
awk 'BEGIN {print log(10)}'
输出:
2.30259


注意:awk字符串下标从1开始不是从0开始

字符串相关函数:

函数描述
sub(src,des)将$0中src第一次出现的子串替换为des(注意:直接将$0替换)
sub(src,des,str)将字符串str中第一次出现的src替换为des。(注意:直接将str替换)
gsub(src,des)将$0中的src全部替换为des,若0中包含src,则返回1否则返回0(注意:直接将$0替换)
gsub(src,des,str)将字符串str中的所有src替换为des(注意:直接将str替换)
index(str,substr)返回str中字符串substr首次出现的位置,位置从1开始,若未找到则返回0
length(str)返回str的长度
match(str, substr)测试str中是否存在子串substr
split(str,result,sep)将str以sep为分割符分割为数组,并存到result中
printf(format,…)格式化输出,与C语言类似
substr(str,start)返回从start开始一直到最后的子字符串,与C++类似
substr(str,start,n)返回从start开始长度为n的子字符串,与C++类似

常用printf format

format说明
%cascii字符
%d整数
%e浮点数,科学计数法
%f浮点数(如1.234)
%o八进制数
%x十六进制数
%s字符串

更多format详见(http://wiki.jikexueyuan.com/project/awk/pretty-printing.html)

#sub测试
awk 'BEGIN {s="aaabbbaaaccc";sub("aaa","1",s);print s}'
输出:
1bbbaaaccc

# gsub(r,s)测试
awk '{gsub("t","s");print $0}' ./score.txt
输出:
13331264 som   grade4 94
13342010 marry grade4 90
13315012 jemmy grade1 85
13323089 jane  grade2 80

# gsub(r,s,t)测试
awk '{gsub("133", "45",$1);print $0}' ./score.txt  
输出:
4531264 tom grade4 94
4542010 marry grade4 90
4515012 jemmy grade1 85
4523089 jane grade2 80

# index(s,t)测试
awk '{r = index($2,"m");print r}' ./score.txt
输出:
3
1
3
0

# 测试length
awk '{print length($2)}' ./score.txt
输出:
3
5
5
4

# 测试match
awk '{print match($2,"to")}' ./score.txt
输出:
1
0
0
0
# split测试
awk 'BEGIN {print split("this is a test",result, " "); for(k in result) {print k":"result[k]}}'

# substr测试
awk 'BEGIN {s="aaabbbccc";print substr(s,2)}'
输出:
aabbbccc

其他常用函数

函数描述
getline读取下一行,并将读出的行数据存储到$0中,当处理下一条记录的时候,继续向后面的行进行读取
next停止当前记录的处理,并继续处理下一条记录
nextfile停止处理当前文件,并继续处理下一个文件
exit终止执行当前脚本,
delete删除数组中的元素
#使用getline实现将奇偶行合并
awk '{s=$0;getline;s=s" "$0;print s}' ./data

awk 'BEGIN {arr[0]=1;arr[1]=2;arr[2]=3;delete arr[0];delete arr[1]; for (item in arr) {print arr[item]}}'
3

AWK几个例子

文件去重并统计相同记录出现次数(保留记录原来的顺序)
test.txt
111
222
111
333
444
# !的优先级高于++,读到一条记录,首先判断记录是否存在于arr中,若不存在,添加到数组中并将该记录数出现次数+1,否则打印
awk '!arr[$0]++' test.txt

# 统计每条记录出现的次数
awk '{!arr[$0]++} END {for (k in arr) print k,arr[k]}' test.txt
文件内容合并
test.txt.1
111
555
666

awk '{if(!arr[$0]) {print $0; arr[$0]++}}' test.txt test.txt.1
找出文件A中存在且文件B中不存在的记录
A:
111
222
333
444

B:
333
444

#计算a.txt-(a.txt并a.txt)
awk 'NR==FNR {a[$0]=1} NR>FNR {if (!a[$0]) print $0}' b.txt a.txt
输出:
111
222
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值