awk 是 Linux/UNIX 下的用来操纵数据和产生报告的程序语言。 Nawk 是新的版本, gawk
是 Gnu 版本。awk 可用于命令行的简单操做,也能够写入大的应用程序。由于 awk 能够操纵数据,因此它是 Shell脚本和管理小型数据库中必需的工具。linux
awk 执行过程分为三个阶段:读输入文件以前执行的代码段(由BEGIN关键字标识);主循环执行输入文件的代码段;读输入文件以后的代码段(由END关键字标识)。可参考下图c++
awk 结构由模版和动做组成。模版用于筛选数据行,一般由正则或条件表达式构成;动做是由一对大括号包裹的代码组成。他们都是可选的。正则表达式
#模式能够是正则、条件表达式或两者的结合。模式不须要写在大括号内 #模式规定了触发大括号内的动做的条件 awk '/root/' txt.log #只有模版,输出含有root的行 awk -F : '$3 == $4' txt.log #只有模版,输出uid=gid的行 awk -F : '{if($3 == $4) echo print $0}' txt.log #区别于模式,动做要写在括号内 awk '/root/{print $0}' txt.log #{}中是动做 awk '{print $0}' txt.log #只有动做,表示处理全部输入行 #范围匹配 '/root/, /mail/' 等同于sed awk -F: '/root/, /daemon/' txt.log #多个语句 awk -F: '/root/{print $0}{print $1}' txt.log #一个模版只能结合一个动做大括号,后一个是新的开始
两种调用模式:awk -F 域分隔符 'awk程序段' 输入文件 或 awk -f xx.awk 输入文件shell
记录和域:awk 将文件行定义为记录,行中的字符串定义为域。域之间用空格、Tab键或其它字符分割。$为域操做符,$0表示整行记录,$1...$n 表示第几个域,也支持表达式 $(a+b) a,b 为整数。-F指定域分隔符,能够是单个字符或正则表达式,默认是空格,Tab被认为是多个空格。字符串跟变量用双引号拼接。数据库
awk -F ':' '{print NF}' txt.log # 一个冒号 awk -F ':+' '{print NF}' txt.log # 为正则时以贪婪匹配为准且第一个字符不会被解析为正则符号
不须要声明能够直接使用,类型是由其内容决定的,变量名区分大小写。编程
数据类型:数字(整型和浮点型 )、字符串、null、数组数组
赋值语句跟C语言相同,再也不赘述,默认初始化为0或空字符。bash
#变量的使用 awk -F ':' 'BEGIN{one=1;two=2;print res} {res+=$(one+two);print res' txt.log
awk 内置了许多有用的变量,可使用man命令细查,下边列出经常使用的函数
变量名 | 释义 |
---|---|
ARGC | 命令行中参数的个数 |
AGRIND | 命令行中当前文件的位置,下标从0开始 |
ARGV | 命令行参数的数组 |
ENVIRON | 环境变量管理数组 |
FILENAME | 当前文件名 |
FNR | 浏览每一个文件的记录数 |
FS/RS | 域分隔符,默认空格 | 记录分隔符,默认空格 |
IGNORECASE | 布尔值,为真则忽略大小写匹配 |
NF/NR | 当前记录中域数量,每行有可能不一样 | 当前记录数,不一样于FNR,它记录的是总行数 |
OFMT/OFS/ORS | 数字输出格式 | 输出域分隔符、默认空格 | 输出记录分隔符,默认换行符 |
SUBSEP | 数组下标分隔符,默认\034,能够用来模拟实现二维数组 |
awk 支持关联数组,下标也能够是变量。使用for (key in array) array[key] 来遍历工具
#数组赋值、删除【delete】、遍历【for in】、长度【length()】 awk -F: '{name[NR]=$1;} END{print length(name);delete name[1];for(n in name) print n, name[n]}' txt.log #注意:name["a"]=3 if("a" in name) print "exist" in 能够断定键是否存在
能够经过命令行参数将变量传递到awk 的BEGIN 块里,有两种方式
#-v 参数传递变量 awk -v a=1 -v b="hi dude" 'BEGIN{print a, b}' #awk 脚本 ##======test.awk======== # {print a, b} ##====================== awk -f test.awk a=1 b="hi dude" txt.log #在begin模块访问不了参数变量
包括整数运算,比较运算符、逻辑运算符 跟C语言相同。只是多了 x~/y/ x!~ /y/ 两个正则匹配符
#关系运算符 > >= < <= == != ~ !~ awk -F: '$0 ~ /root/' txt.log # 正则匹配符 awk -F: '$0 !~ /root/' txt.log # !表示非 awk -F: '$3>=20 {print $1}' txt.log # == != #条件表达式 awk -F: '{max=$4>$3 ? $4 : $3;print $0,max}' txt.log #布尔运算符 && || ! awk -F":+" 'NF == 6 || $1 ~ /root/ {print $0 " show"}' txt.log #算术运算 + - * /(非整除) % ^或** ++ -- awk -F: '{print $3 "+10=" $3+10, x+=1}' txt.log awk -F: '{print $3 "/2=" $3/3}' txt.log # 保留6位有效小数 awk -F: '/^$/ {++x} END{print "有"x"个空行"}' txt.log # 未初始化的整型默认为0
if 语句同C语言一致,属于动做语句。
#if 用法示例,多个语句须要大括号,之间分号间隔 awk -F: '{ if($1 ~/root/) msg="root";\ else if($1 ~/mail/) msg="mail";\ else msg="unkonwn"; }END{print msg}' txt.log
循环示例
#while 相似还有do while awk -F: '{i=1;while($i<=NF){print NF, $i, $i++;}}' txt.log #for 有两种模式 for (n in array) 专用于数组 awk -F: '{for(i=1;i<=NF;i++)print NF,$i;}' txt.log #循环控制 continue break 与C语言同 next 会阻止其在同一个命令块中后边的命令,而后从头执行 exit 会退出整个awk 命令块,直接跳转到END模块(若是有)
也能够自定义函数,使用较少,主要介绍系统函数。
#字符串函数示例 #sub(/正则/,"替换字符","目标字符串,可省略默认是$0"),使用的是贪婪匹配,且只替换第一次匹配 #gsub 与sub 语法格式相同,区别在因而所有替换 awk -F: '{sub(/r.+t/, "===");print}' txt.log #是贪婪匹配 #index(string, substring) 返回子串第一次出现的位置,下标从1开始 awk -F: 'BEGIN {print index("hello", "l")}' #length(string) 返回字符数,省略参数表示则默认为$0 #substr(string,start=1,length),省略或超出总长都默认到末尾,不能为负数 #match(string, /pattern/)返回第一次匹配的字串位置并保存在RSTART中,字串长度保存在RLENGTH,不匹配返回0 awk -F: 'BEGIN {start= match("Good old USA", /[A-Z]+$/);print RSTART,RLENGTH,start}' #toupper(str), tolower(str) 大小写转换,仅gawk支持;sprintf(str) 格式化输出 #split(string,array,sep=FS),将返回的数组放到array中,默认分隔符为FS,无匹配则返回整个字符到第一个元素中 awk -F: 'BEGIN{split("2017-11-29",date);print date[1];}' #时间函数 systime strftime #systime() 返回unix时间戳(秒) awk 'BEGIN{print systime()}' #strftime("格式符" [,时间戳=当前]) 格式符与C库strftime 一致,可 man strftime 查看 awk 'BEGIN{print strftime("%D")}' #数学函数 int rand srand #int() 去掉小数部分,没有舍入 #rand() 生成0-1的随机小数,每次执行产生的值都同样 awk '/root/{print rand()}' txt.log #执行两遍,输出的结果同样 #srand(x) 生成rand的种子,x默认是时间戳 awk 'BEGIN{srand()} /root/{print 1 + int(25*rand())}' txt.log
#输出重定向(>和>>), 文件路径需要引号包裹,文件一旦被打开,必须明确关闭或等待awk程序结束 awk -F: '$3>20 {print $0>"/tmp/test.log"}' txt.log #输入从新定向 getline 函数。它能够从标准输入、管道,外部文件获取下一行输入。 #会修改NF,NR,FNR,若是获得一个记录返回1,达到文件末尾返回0,出现错误返回-1 #从管道获取 awk 'BEGIN{"date"|getline now;print now}' awk 'BEGIN{while("ls"|getline)print}' #从命令行获取 awk 'BEGIN{printf "What is your name?";\ getline name <"/dev/tty"}\ $1~name{print "found"name"on line",NR"."}\ END{print "See ya,"name"."}' txt.log #从外部文件获取 awk 'BEGIN{while(getline < "/etc/passwd">0)lc++;print lc}'
管道:若是在awk中已打开一个管道,那么在打开下一个管道前必须关闭它,管道符号右边能够经过双引号关闭管道。
system("linux shell") 能够执行系统命令,正常的执行系统命令须要用双引号包裹