详细介绍AWK的文章,推荐去朱双印的个人博客,10分好评的个人博客,传送门
本文章仅为个人精简参考使用,不适合初学者,详细的介绍文章,请用以上的传送门
也可以稍微参考一下博客园:https://www.cnblogs.com/isykw/p/6258781.html
也可以参考CSDN https://blog.csdn.net/sunchengquan/article/details/80276842
本文包括
- AWK简介
- awk基本语法
- awk常用命令选项
- awk的几种模式
- awk的内置变量
- awk设置定义变量
- awk模式的定义,空模式,关系运算模式,BEGIN模式,END模式,正则表达式模式
- awk 在用 {x,y} 这种正则时,需要加参数
- awk 支持if else, for ,while等控制语句
- awk 计算日志中ip的数量
- awk 把两个文件内的指定列,合并成一个文件
- awk编程,善用FNR NR
- awk数学运算
- awk 生成随机数(利用awk的自带函数)
- awk中使用shell的环境变量
AWK简介
awk是由Alfred Aho 、Peter Weinberger 和 Brian Kernighan这三个人创造的,awk由这个三个人的姓氏的首个字母组成。
awk早期是在unix上实现的,所以,我们现在在linux的所使用的awk其实是gawk,也就是GNU awk,简称为gawk,awk还有一个版本,New awk,简称为nawk,但是linux中最常用的还是gawk。
awk其实是一门编程语言,它支持条件判断、数组、循环等功能。所以,我们也可以把awk理解成一个脚本语言解释器。
awk 更适合格式化文本,以文件的行为处理单位的,对文本进行较复杂格式处理
AWK基础
基本语法如下
awk [options] 'Pattern{Action}' file
awk '{
BEGIN{stat1}
BEGIN{stat2}
pattern1{action1}
pattern2{action2}
...
patternn{actionn}
{默认动作,无条件,始终执行}
END{stat1}
END{stat2}
}'
常用命令选项
-F 指定输入分隔符,fs可以是字符串或正则表达式,如 -F ':' , 默认的隔符是空格
-v var=value -v是一种选项,var是一个变量的名称,value是一个变量的值,有很多内置的变量名称
-v FS=':' 指定输入分隔符为: 和 -F 类似
-v OFS='###' 指定 输出分隔符 ,默认输出分隔符为空格,可以换成任意的输出分割符
-f scripfile 从脚本文件中读取awk命令
awk命令插入一个文件,并使awk程序可执行,然后awk命令解释器作为脚本的首行,一遍通过键入脚本名称来调用。
相当于shell脚本首行的:#!/bin/sh
可以换成:#!/bin/awk
如果只是显示/etc/passwd的账户
#cat /etc/passwd |awk -F ':' '{print $1}' root daemon bin sys
AWK 包含两种特殊的模式:BEGIN 和 END。
BEGIN 模式指定了处理文本之前需要执行的操作:
END 模式指定了处理完所有行之后所需要执行的操作:
以下实例展示了-v FS 指定输入分隔符 和 -v OFS 指定输出分隔符 指定BEGIN 和 END
awk 处理 /etc/passwd 获取 $1,$7的数据
而账户与shell之间以'++++'分割,
而且在第一行添加文字 "name,shell",
在最后一行添加"blue,/bin/nosh"。
[root@cnblogs ~]# cat /etc/passwd |awk -v FS=':' -v OFS="++++" 'BEGIN {print "name,shell"} {print $1,$7} END {print "blue,/bin/nosh"}' name,shell root++++/bin/bash bin++++/sbin/nologin daemon++++/sbin/nologin ...
... blue,/bin/nosh
awk内置变量
awk有许多内置变量用来设置环境信息,这些变量可以被改变,下面给出了最常用的一些变量。
ARGC 命令行参数个数 ARGV ARGV内置变量表示的是一个数组,这个数组中保存的是命令行所给定的参数。这样解释还是很模糊,不容易理解,我们来看看示例。 ENVIRON 支持队列中系统环境变量的使用 FILENAME awk浏览的文件名 FNR 各文件分别记录的行号 FS FS: field separator设置输入域分隔符,等价于命令行 -F选项 NF 列数,number of the field,当前处理行的总列数(被分成几列) NR 行数,number of the row,当前处理文本行的行号 OFS OFS:output field separator 输出字段分隔符, 默认为空白字符 ORS ORS:output row separator 输出记录分隔符(输出换行符),输出时用指定符号代替换行符 RS RS:row separator 输入记录分隔符(输入换行符), 指定输入时的换行符
除了内置变量,也可以定义自定义变量
有两种定义方法
方法一:-v varname=value 变量名区分字符大小写。
方法二:在program中直接定义。
[root@cnblogs ~]# awk -v myVAR="testVAR" 'BEGIN{print myVAR}' testVAR [root@cnblogs ~]# awk 'BEGIN{myVAR="testVAR";print myVAR}' testVAR
也可以一次定义多个,如
[root@cnblogs ~]# awk 'BEGIN{myVAR1="testVAR1";myVAR2="testVAR2";print myVAR1,myVAR2}' testVAR1 testVAR2
统计/etc/passwd:文件名,每行的行号,每行的列数,对应的完整行内容:
[root@cnblogs ~]# awk -F ':' '{print "filename:" FILENAME ",linenumber:" NR ",columns:" NF ",linecontent:"$0}' /etc/passwd filename:/etc/passwd,linenumber:1,columns:7,linecontent:root:x:0:0:root:/root:/bin/bash filename:/etc/passwd,linenumber:2,columns:7,linecontent:bin:x:1:1:bin:/bin:/sbin/nologin filename:/etc/passwd,linenumber:3,columns:7,linecontent:daemon:x:2:2:daemon:/sbin:/sbin/nologin filename:/etc/passwd,linenumber:4,columns:7,linecontent:adm:x:3:4:adm:/var/adm:/sbin/nologin filename:/etc/passwd,linenumber:5,columns:7,linecontent:lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin filename:/etc/passwd,linenumber:6,columns:7,linecontent:sync:x:5:0:sync:/sbin:/bin/sync filename:/etc/passwd,linenumber:7,columns:7,linecontent:shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
使用printf替代print,可以让代码更加简洁,易读
[root@cnblogs ~]# awk -F ':' '{printf("filename:%10s,linenumber:%s,columns:%s,linecontent:%s\n",FILENAME,NR,NF,$0)}' /etc/passwd filename:/etc/passwd,linenumber:1,columns:7,linecontent:root:x:0:0:root:/root:/bin/bash filename:/etc/passwd,linenumber:2,columns:7,linecontent:bin:x:1:1:bin:/bin:/sbin/nologin filename:/etc/passwd,linenumber:3,columns:7,linecontent:daemon:x:2:2:daemon:/sbin:/sbin/nologin filename:/etc/passwd,linenumber:4,columns:7,linecontent:adm:x:3:4:adm:/var/adm:/sbin/nologin filename:/etc/passwd,linenumber:5,columns:7,linecontent:lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin filename:/etc/passwd,linenumber:6,columns:7,linecontent:sync:x:5:0:sync:/sbin:/bin/sync filename:/etc/passwd,linenumber:7,columns:7,linecontent:shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
AWK模式的概念就是条件
"模式"这个词听上去文绉绉的,不是特别容易理解,那么我们换一种说法,我们把"模式"换成"条件",可能更容易理解,那么"条件"是什么意思呢?我们知道,awk是逐行处理文本的,也就是说,awk会先处理完当前行,再处理下一行,如果我们不指定任何"条件",awk会一行一行的处理文本中的每一行,如果我们指定了"条件",只有满足"条件"的行才会被处理,不满足"条件"的行就不会被处理。这样说是不是比刚才好理解一点了呢?这其实就是awk中的"模式"。
再啰嗦一遍,当awk进行逐行处理的时候,会把pattern(模式)作为条件,判断将要被处理的行是否满足条件,是否能跟"模式"进行匹配,如果匹配,则处理,如果不匹配,则不进行处理。
以下是AWK模式的示例 NF=2 或者 NF>2 是条件,也就是模式
[root@cnblogs ~]# awk 'NF==2 {print $0}' /etc/passwd ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin nscd:x:28:28:NSCD Daemon:/:/sbin/nologin [root@cnblogs ~]# awk 'NF>2 {print $0}' /etc/passwd systemd-network:x:192:192:systemd Network Management:/:/sbin/nologin dbus:x:81:81:System message bus:/:/sbin/nologin polkitd:x:999:998:User for polkitd:/:/sbin/nologin
AWK支持正则表达式匹配
除此之外,还要注意以下两点
1、当在awk命令中使用正则模式时,使用到的正则用法属于"扩展正则表达式"。
2、当使用 {x,y} 这种次数匹配的正则表达式时,需要配合--posix选项或者--re-interval选项。
awk的"模式(Pattern)",
空模式 没有条件,每行都处理
关系运算模式 根据条件,处理符合条件的行
BEGIN 模式
END 模式
正则模式
AWK支持"if...else if...else"这样的"控制语句"
AWK支持for 循环,while 循环,continue,break,do ... while 循环
详细请参考,朱双印的博客:http://www.zsythink.net/archives/2062
#for循环语法格式1 for(初始化; 布尔表达式; 更新) { //代码语句 } #for循环语法格式2 for(变量 in 数组) { //代码语句 } #while循环语法 while( 布尔表达式 ) { //代码语句 } #do...while循环语法 do { //代码语句 }while(条件)
为了方便判断和阅读,最好将多个语句用{}括起来。awk分支结构允许嵌套,其格式为:
示例:
awk 'BEGIN{ test=100; if(test>90){ print "very good" } else if(test>60){ print "good" } else{ print "no pass" } }' very good
自定义变量用; 分号结尾。
while语句
示例:
awk 'BEGIN{ test=100; total=0; while(i<=test){ total+=i; i++; } print total; }' 5050
上图中,我们使用了一个空模式,一个END模式。
如下示例,计算人名出现的次数
awk '{for (i=1;i<=NF;i++) {count[$i]++}} END{for(j in count){print j,count[j]}}' test4
以下示例得到小于100的随机数,使用了rand() 和 srand(),int() 函数
用srand()是因为,如果只使用rand(),第一次的数值不会变化,每次都是一样的随机数
[root@jenkins ~]# awk 'BEGIN{srand();print rand()}' 0.0698597 [root@jenkins ~]# awk 'BEGIN{srand();print 100*rand()}' 79.413 [root@jenkins ~]# awk 'BEGIN{srand();print int(100*rand())}' 73 [root@jenkins ~]#
更多awk函数用法,请参考:
http://www.zsythink.net/archives/2113
https://www.cnblogs.com/isykw/p/6258781.html
按照列合并两个文件
[root@cnblogs ~]# cat a 1 2 1 2 1 2 1 2 1 2 [root@cnblogs ~]# cat b 3 4 3 4 3 4 3 4 3 4 [root@cnblogs ~]# awk '{if(FNR==NR) {d[FNR]=$0}} {if(FNR!=NR){print d[FNR],$0}}' a b 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 [root@cnblogs ~]# awk '{if(FNR==NR) {d[FNR]=$1}} {if(FNR!=NR){print d[FNR],$2}}' a b 1 4 1 4 1 4 1 4 1 4 [root@cnblogs ~]# awk 'FNR==NR {x[FNR]=$0} FNR!=NR{print x[FNR],$0}' a b 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 [root@cnblogs ~]#
a和b 有相同的列,把相同的列结合在一起
[root@cnblogs ~]# cat a 116 t1 117 t2 118 t3 [root@cnblogs ~]# cat b 116 1000 117 1500 118 800 [root@cnblogs ~]# awk 'NR==FNR{a[$1]=$2}NR!=FNR{print a[$1],$2}' a b t1 1000 t2 1500 t3 800 [root@cnblogs ~]# awk '{print NR ,FNR ,$1,$2}' a b 1 1 116 t1 2 2 117 t2 3 3 118 t3 4 1 116 1000 5 2 117 1500 6 3 118 800
awk数学运算示例
求1除以3结果保留一位小数,并且用%号表示数值
[root@cnblogs ~]# t1=1 [root@cnblogs ~]# t2=3 [root@cnblogs ~]# awk 'BEGIN{printf "%.1f%\n",("'$t1'"/"'$t2'")*100}' 33.3% [root@cnblogs ~]#
awk中使用shell的环境变量
第一种方法,使用-v ,定义变量可以引用变量
[root@cnblogs ~]# abc=66666
[root@cnblogs ~]# awk -v myVAR="$abc" 'BEGIN{print myVAR}'
66666
[root@cnblogs ~]# var="test" [root@cnblogs ~]# awk -v var="$var" 'BEGIN{print var}' test
第二种方法,在awk中直接引用,使用字符串变量 ,
注意使用前格式必须是先用单引号括住再用双引号括住,如:
"'$var'"
如果变量中含有空格或者特殊符号,需要如下
"'"$var"'"
如果不是用脚本文件方式执行,直接在shell里执行,需要先用export var=test 导出为环境变量,
这样其后的awk子进程才会有该变量。
[root@cnblogs ~]# var="test" [root@cnblogs ~]# awk 'BEGIN{print "'$var'"}' test
[root@cnblogs ~]# var="this is a test" [root@cnblogs ~]# awk 'BEGIN{print "'"$var"'"}' this is a test [root@cnblogs ~]#
[root@cnblogs ~]# export var="this is a test" [root@cnblogs ~]# awk 'BEGIN{print "'"$var"'"}' this is a test [root@cnblogs ~]#
所有IP的连接数统计
awk 'BEGIN{while("netstat -an"|getline){if( $5 ~ /[1-255]/){split($5,t1,":");tarr[t1[1]]++;}}for(k in tarr){print k,tarr[k] | "sort -r -n -k2";}};'