awk文本处理工具原理及使用
awk是一种编程语言,用于在linux/unix下对文本和数据进行处理。数据可以来自标准输入(stdin)、一个或多个文件,或其它命令的输出。它支持用户自定义函数和动态正则表达式等先进功能,是linux/unix下的一个强大编程工具。它在命令行中使用,但更多是作为脚本来使用。awk有很多内建的功能,比如数组、函数等,这是它和C语言的相同之处,灵活性是awk最大的优势 。
1.常用命令选项:
命令 | 意义 |
---|---|
-F | 指定输入分隔符,可以是字符串或正则表达式,如-F: |
-v | var=value 赋值一个用户定义变量,将外部变量传递给awk(每定义一个变量一个参数-v) |
-f | scriptfile 从脚本文件中读取awk命令 |
-v | OFS=”\t” OFS变量表示输出分隔符(每定义一个变量一个参数-v |
2.模式和操作:
awk脚本是由模式和操作来组成的
模式可以是以下任意一个:
①/正则表达式/: 使用通配符的扩展集,在”/” “/”这两根斜线之间的是正则表达式
②关系表达式: 使用运算符进行操作,可以是字符串或数字的比较测试
③模式匹配表达式: 用运算符 ~(匹配)和 ~!(不匹配)
④BEGIN语句块、pattern语句块、END语句块
操作由一个或多个命令、函数、表达式组成,之间由换行符或分号隔开,并位于大括号内,主要部分是 :
①变量或数组赋值
②输出命令
③内置函数
④控制流语句
3.基本结构:
awk ‘BEGIN{ print “start” } pattern{ commands } END{ print “end” }’ file
一个awk脚本通常由:BEGIN语句块、能够使用模式匹配的通用语句块、END语句块3部分组成,这三个部分是可选的。
任意一个部分都可以不出现在脚本中,脚本通常是被单引号或双引号中
awk ‘BEGIN{ i=0 } { i++ } END{ print i }’ filename
awk “BEGIN{ i=0 } { i++ } END{ print i }” filename
#内置变量
[root@localhost ~]# more filename
aa 100
bb 353
[root@localhost ~]# awk '{ print $NF }' filename
100
353
#打印出一行中的最后一个字段;$(NF-1)
[root@localhost ~]# awk '{ print NF }' filename
2
2
#总字段数,也可组合使用
[root@localhost ~]# awk '{ printf("%s^%s\n",$1,$2) }' filename
aa^100
bb^353
[root@localhost ~]# awk 'END{ print NR }' filename
2
#统计文件中的行数,命令只用了END语句块,在读入每一行的时,awk会将NR更新为对应的行号,当到最后一行NR的值就是最后一行的行号,所以END语句块中的NR就是文件的行数
[root@localhost ~]# seq 100 | awk 'BEGIN{sum=0} {sum+=$1} END{print "总和:"sum}'
总和:5050
#一个每一行中第一个字段值累加
#外部变量传递
[root@localhost ~]# echo | awk -v VARIABLE=$VAR '{ print VARIABLE }'
10000
[root@localhost ~]# var1="aaa"
[root@localhost ~]# var2="bbb"
[root@localhost ~]# echo | awk '{ print v1,v2 }' v1=$var1 v2=$var2
aaa bbb
[root@localhost ~]# echo | awk '{print ENVIRON["PATH"]} '
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
#awk运算与判断
#+ - 加、减
#* / & 乘、除、求余
#+ - ! 一元加、减、逻辑非
#^ ** 求幂
#++ -- 增加或减少,作为前缀或后缀
[root@localhost ~]# awk 'BEGIN{ a=1; print a++,++a;}'
1 3
#赋值运算符
#= += -= *= /= %= ^= **= 赋值语句
#a+=5; 等价于:a=a+5; 其它同类
#逻辑运算符
#|| 逻辑或
#&& 逻辑与
[root@localhost ~]# awk 'BEGIN{a=1;b=2; print (a>5 && b<=2),(a>5 || b<=2);}'
0 1
#正则运算符
#~ ~! 匹配正则表达式和不匹配正则表达式
[root@localhost ~]# awk 'BEGIN {a="100testa"; if(a ~ /^100*/) {print "ok";}}'
ok
#关系运算符
#< <= > >= != == 关系运算符
[root@localhost ~]# awk 'BEGIN{a=11; if(a >= 9) {print "ok";}}'
ok
#其它运算符
#$ 字段引用
#空格 字符串连接符
#a>b?y:n 三目运算条件表达式
#in 数组中是否存在某键值
[root@localhost ~]# awk 'BEGIN{a="b";print a=="b"?"ok":"err";}'
ok
[root@localhost ~]# awk 'BEGIN{a="b";arr[0]="b";arr["b"]="c";print (a in arr);}'
1
[root@localhost ~]# awk 'BEGIN{a="b";arr[0]="b";arr[1]="c";print (a in arr);}'
0
#高级输入输出
[root@localhost ~]# more filename
aa 100
bb 353
cc 234
total 1000
[root@localhost ~]# awk '{if($1=="total"){next};print }' filename
aa 100
bb 353
cc 234
[root@localhost ~]#
#awk中next语句,相当于其他编程语言的continue
[root@localhost ~]# more text.txt
web01[192.168.2.100]
httpd ok
tomcat ok
sendmail ok
[root@localhost ~]# awk '/^web/{T=$0;next;}{print T":"$0;}' text.txt
web01[192.168.2.100]:httpd ok
web01[192.168.2.100]:tomcat ok
web01[192.168.2.100]:sendmail ok
#分析发现需要将包含有“web”行进行跳过,然后需要将内容与下面行合并为一行
#简单地读取一条记录
[root@localhost ~]# awk 'BEGIN{ "date" | getline out; print out }' test
Mon Nov 5 16:57:31 CST 2018
#输出到一个文件 输出重定向
[root@localhost ~]# more file1
hello linux!
[root@localhost ~]# echo | awk '{printf("hello word!") > "file1"}' 覆盖原内容
hello word!
[root@localhost ~]# echo | awk '{printf("hello word!") >> "file1"}' 追加到原内容后
[root@localhost ~]# more file1
hello linux!hello word!
#设置字段定界符
[root@localhost ~]# awk -F: '{ print $NF }' /etc/passwd
/bin/bash
/sbin/nologin
/sbin/nologin
...(省略后面内容)
[root@localhost ~]# awk 'BEGIN{ FS=":" } { print $NF }' /etc/passwd
/bin/bash
/sbin/nologin
/sbin/nologin
...(省略后面内容)
[root@localhost ~]# awk 'BEGIN{FS=":"; OFS="-->"} {print $1,$3}' /etc/passwd
root-->0
bin-->1
daemon-->2
...(省略后面内容)
#在BEGIN语句块中则可以用OFS=“定界符”设置输出字段的定界符
测试:
#名称,电话,过去三个月捐款数
Mike Harrington:[510] 548-1278:250:100:175
Christian Dobbins:[408] 538-2358:155:90:201
Susan Dalsass:[206] 654-6279:250:60:50
Archie McNichol:[206] 548-1348:250:100:175
Jody Savage:[206] 548-1278:15:188:150
Guy Quigley:[916] 343-6410:250:100:175
Dan Savage:[406] 298-7744:450:300:275
Nancy McNeil:[206] 548-1278:250:80:75
John Goldenrod:[916] 348-4278:250:100:175
Chet Main:[510] 548-5258:50:95:135
Tom Savage:[408] 926-3456:250:168:200
Elizabeth Stachelin:[916] 440-1763:175:75:300
1.显示所有电话号码
[root@localhost ~]# awk -F: '{print $2}' awk_text
[510] 548-1278
[408] 538-2358
[206] 654-6279
[206] 548-1348
[206] 548-1278
...(省略后面内容)
2.显示Dan的电话号码
[root@localhost ~]# awk -F: '/^Dan/{print $2}' awk_text
[406] 298-7744
3.显示Susan的名字和电话号码
[root@localhost ~]# awk -F: '/^Susan/{print $1 ,$2}' awk_text
Susan Dalsass [206] 654-6279
4.显示所有以D开头的姓
[root@localhost ~]# awk -F: '{print $1}' awk_text|awk '{print $2}' | awk '/^D/'
Dobbins
Dalsass
5.显示所有以一个C或E开头的名
[root@localhost ~]# awk -F: '{print $1}' awk_text | awk '{print $1}' | awk '/^[CE]/'
Christian
Chet
Elizabeth
[root@localhost ~]# awk -F: '{print $1}' awk_txet | awk '/^[CE]/{print $1}'
Christian
Chet
Elizabeth
[root@localhost ~]#
6.显示所有只有四个字符的名,这里可以使用length函数,举例: length(1)==10 1字符为10
[root@localhost ~]# awk -F: '{print $1}' awk_text | awk '{if(length($1) == 4)print $1}'
Mike
Jody
John
Chet
7.显示所有区号为916的人名
[root@localhost ~]# awk -F: '/916/{print $1}' awk_text
Guy Quigley
John Goldenrod
Elizabeth Stachelin
8.显示Mike的捐款.显示每个值时都有以$开头.如$250$100$175
[root@localhost ~]# awk -F: '/^Mike/{print "$"$3"$"$4"$"$5}' awk_text
$250$100$175
9.显示姓,其后跟一个逗号和名
[root@localhost ~]# awk -F: '{print $1}' awk_text | awk '{print $2,",",$1}'
Harrington , Mike
Dobbins , Christian
Dalsass , Susan
McNichol , Archie
Savage , Jody
...(省略后面内容)