awk学习笔记

参考资料:《sed & awk》读书笔记之 awk 篇


awk,sed,grep俗称linux下的三剑客。

awk是一门模式匹配的编程语言,因为它的主要功能是用于匹配文本并处理,同时它有一些编程语言才有的语法,例如函数、分支循环语句、变量等,当然比起我们常见的额编程语言,awk相对简单。

使用awk我们可以做以下事情:
  • 将文本文件视为由字段和记录组成的文本数据库;
  • 在操作文本数据库的过程中使用变量;
  • 能够使用数学运算和字符串操作;
  • 能够使用常见的编程结构,例如条件分支和循环;
  • 能够格式化输出;
  • 能够自定义函数;
  • 能够在awk脚本中执行UNIX命令;
  • 能够处理UNIX命令的输出结果;

命令行语法:
  1. awk [-F ERE] [-v assignment] ... program [argument]
  2. awk [-F ERE] -f profile ... [-v assignment] ... [argument]
说明:awk的脚本可以写到一个文件中,通过-f参数指定,可以同时指定多个脚本,它们会按照在命令行中出现的顺序连接在一起。program一般由多个pattern和action序列组成,当读入的记录匹配pattern时,才会执行相应的action命令。-F参数定义字段分隔符。-v定义awk变量,形式同awk中的变量赋值,即name = value,赋值发生在awk处理文本之前。

awk的输入被解析成多个记录(Record),默认情况下记录的分隔符是\n,因此可以认为一行就是一个记录,记录的分隔符可以通过内置变量 RS更改,如果将RS赋值为空,那么连续不为空行的所有行为一个记录,并且强制字段分隔符为回车(FS不能被赋值)。每个记录被进一步地分隔成多个字段(Field),默认情况下字段的分隔符是空白符,也可以通过-F ERE选项或者内置变量 FS更改。可以通过$1,$2...来访问对应位置的字段,同时$0存放整个记录。 内置变量NF记录着字段的个数,所以$NF表示最后一个字段。

举几个简单例子:
input:
echo "1:2:3" | awk -F : '{print $1 " and " $2 " and " $3}'
output:
1 and 2 and 3

input:
echo | awk -v a = 1 'BEGIN {print a}'
output:
1
从上面可以看到,通过-v设置的变量在BEGIN的位置就可以访问了。BEGIN是一个特殊的pattern,它在awk处理输入之前就会执行,可以认为是一个初始化语句,与此对应的还有END。

argument有两种形式,分别是输入文件和变量赋值。
可以指定多个输入文件,如果输入文件的文件名为'-',表示从标准输入读取内容。
变量赋值必须位于脚本参数的后面,与文件名参数无先后顺序的要求,但是位于不同位置的赋值它的执行时机不同。
三个简单例子:
有两个文本文件:a和b。
input:
awk 'BEGIN{print "BEGIN: " var}{print "PROCESS: " var}END{print "END: " var}'  var = 1 a
output:
BEGIN:
PROCESS: 1
END: 1

input:
awk 'BEGIN{print "BEGIN: " var}{print "PROCESS: " var}END{print "END: " var}' a var = 1
output:
BEGIN:
PROCESS:
END: 1
 
input:
awk 'BEGIN{print "BEGIN: " var}{print "PROCESS: " var}END{print "END: " var}' a var = 1 b
output:
BEGIN:
PROCESS:
PROCESS: 1
END: 1

在脚本中可以自定义函数,function name(parameter list){ statements },参数默认是局部变量无法在函数之外访问,而在函数中定义的变量为全局变量,可以在函数之外访问。

模式(Pattern)有以下几种情况:
  • /regular expression/:扩展的正则表达式;
  • relational expression:关系表达式,例如大于小于等于,关系表达式结果为true表示匹配;
  • BEGIN:特殊的模式,在第一个记录处理之前被执行,常用于初始化语句的执行;
  • END:特殊的模式,在最后一个记录处理之后被执行,常用于输出汇总信息;
  • pattern,patterm:模式对,匹配两者之间的所有记录;

例子:输出匹配3的字段
input:
seq 1 20 | awk '/3/ {print}'
output:
3
13
相反,可以在正则表达式之前加上'!',表示不匹配,例如:
input:seq 1 5 | awk '!/3/ {print}'
output:
1
2
4
5

除了BEGIN和END这两个特殊模式,其余模式都可以使用'&&'或者'||'。

前面的匹配都是整行匹配,有时候仅仅需要匹配某个字符,这样我们可以用表达式$n ~ /ERE/,例如:
input:
awk '$1 ~ /ser/ {print}' /etc/passwd
output:
username:x:1000:1000::/home/kodango:/bin/bash

NR表示要显示的行数(可赋值),例如:
input:
seq 1 5 | awk 'NR == 1 {print}'
output:
1

数组在awk中下标可以为数字或者字符串;可以用for(item in array)遍历, item是下标;也可以在if(item in array)中进行判断。



变量名
描述
ARGC
命令行参数的个数,即ARGV数组的长度
ARGV
存放命令行参数
CONVFMT
定义awk内部数值转换成字符串的格式,默认值“%.6g”
OFMT
定义输出时数值转换成字符串的格式,默认值为“%.6g”
ENVIRON
存放系统环境变量的关联数组
FILENAME
当前被处理的文件名
NR
记录的总个数
FNR
当前文件中记录的总个数
FS
字段分隔符,默认为空白
NF
每个记录中的字段的个数
RS
记录的分隔符,默认为回车
RLENGTH
被match函数匹配的子串长度
RSTART
被match函数匹配的子串位于目标字符串的起始下标

说明:
ARGV存放命令行参数,并且排除命令行选项(例如-v/-f),因此事实上ARGV只存储argument的部分,即文件名以及变量赋值两部分的内容,可以对ARGV修改,例如:
假设有a,b两个文件,它们各有一行内容:file a和file b。
input:
awk 'BEGIN{ARGV[1] = ""} {print}' a b
output:
file b
也可以删除ARGV达到以上例子的效果:
input:
awk 'BEGIN{delete ARGV[1]} {print}' a b
增加ARGV则需要先将ARGC+1,然后再增加ARGV,例:
input:
awk 'BEGIN{ARGC+=1; ARGV[1]="a"} {print}'
output:
file a

 CONVFMT和OFMT:
input:
awk 'BEGIN{
     printf "CONVFMT=%s, num=%f, str=%s", CONVFMT, 12.11, 12.11
}'
output:
CONVFMT=%.6g, num=12.110000, str=12.11
可以通过更改CONVFMT定义自己的转换格式:
input:
awk 'BEGIN{
     CONVFMT="%d";
     printf "CONVFMT=%s, num=%f, str=%s", CONVFMT, 12.11, 12.11
}'
output:
CONVFMT=%d, num=12.110000, str=12
OFMT与其类似,只不过是影响输出时候数字转换成字符串的格式:
input:
awk 'BEGIN{ OFMT="%d"; print 12.11}'
output:
12

ENVIRON是存放系统环境变量的数组。

语句:包括print,printf,delete,break,continue,exit,next。其中exit是退出awk的处理直接进入END处理。next是跳转到下一个记录并重新回到脚本的最开始处执行。print输出时,字段之间的分隔符可以由OFS重新定义。print的输出还可以重定向到某个文件或某个命令。
重定向命令的例子:
假设存在一个文件num.list,每行内容分别是,1,3,2,9,5。
input:
awk '{print | "sort -n"}' num.list
output:
1
2
3
5
9

awk的函数包括:
  • 数学函数
  • 字符串函数
  • I/O处理函数
  • 用户自定义的函数

数学函数:
awk支持以下数学函数:
  • atan2(y, x)反正切函数;
  • cos(x);
  • sin(x);
  • exp(x)以自然对数e为底的指数函数;
  • log(x)计算以e为底的对数值;
  • sqrt(x)绝对值;
  • int(x)将数值转换为整数;
  • rand()返回0到1的一个随机数值,不包含1;
  • srand([expr])设置随机种子,如果参数为空,默认使用当前时间为种子;


字符串函数:
  • sub(ere, repl[,in])将in中匹配ere的部分替换成repl,如果in参数省略,默认使用$0。例如:
     input:
     echo "hello, world" | awk '{print sub(/ello/, "i"); print}'
     output:
     1
     hi, world
     在repl参数中&是一个元字符,它表示匹配的内容,例如:
     input:
     awk 'BEGIN{var = "username"; sub(/username/, "hello, &", var);print var}'
     output:
     hello, username
  • gsub(ere,repl[,in])同sub()函数功能类似,但是gsub()函数是全局替换。
  • index(s,t)返回字符串t在s中出现的位置(这里位置是从1开始计算)
  • length[([s])]s缺省则默认参数为$0
  • match(s,ere)返回字符串s匹配ere的起始位置,不匹配返回0。该函数会定义RSTART和RLENGTH两个内置变量。RSTART和返回值相同,RLENGTH记录匹配子串的长度,如果不匹配则为-1。
  • split(s,a[,fs])分隔字符串,存到数组a中,如果fs为空,则默认使用FS进行分隔。函数返回值为分隔的个数。
  • sprintf(fmt,expr,expr,...)类型printf,不过不会输出而是产生返回值。
  • substr(s,m[,n])返回从位置m起,长度为n的子串。
  • tolower(s)。
  • toupper(s)。

I/O处理函数:
  • getline:
     例子:设想有一个statement.txt,内容每行分别为st1,st2,st3。
     input:
     awk 'BEGIN{ while("cat statement.txt" | getline var) print var}'
     output:
     st1
     st2
     st3
     如果getline后没有var来承接,则直接写到$0,同时NF值被更新。
     也可以直接getline,例如while(getline)print $0。还可以getline [var] < expression,从expression中重定向输入。
  • close:关闭已经打开的文件或者管道。
  • system:用于执行外部命令。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值