介绍awk是一个强大的文本分析工具。与grep搜索和sed编辑器相比,awk在分析数据和生成报告方面尤为强大。简单来说,awk是逐行读取文件,将每一行以空格作为默认分隔符进行切片,然后对切片的部分进行各种分析处理。awk有3个不同版本:awk、nawk和gawk,不特别说明,一般指gawk,gawk是AWK的GNU版本。awk的名字来源于其创始人AlfredAho、PeterWeinberger和BrianKernighan姓氏的首字母。AWK实际上有自己的语言:AWK编程语言,三位创建者已将其正式定义为“样式扫描和处理语言”。它允许您创建读取输入文件、排序数据、处理数据、对输入执行计算、生成报告和无数其他功能的短程序。使用方法awk'{pattern+action}'{filenames}虽然操作可能很复杂,但语法总是相同的,其中pattern表示AWK在数据中寻找什么,而action是当一个找到匹配顺序。大括号({})不需要在程序中始终如一地出现,但它们用于根据特定模式对指令序列进行分组。pattern是要表达的正则表达式,用斜杠括起来。awk语言最基本的功能是根据指定的规则浏览和提取文件或字符串中的信息。awk提取信息后,就可以进行其他文本操作了。完整的awk脚本通常用于格式化文本文件中的信息。通常,awk在一行中处理一个文件。awk接收文件的每一行,然后执行相应的命令来处理文本。调用awk的方法1、命令行方式awk[-Ffield-separator]'commands'input-file(s)其中commands是真正的awk命令,[-Ffieldseparator]是可选的。输入文件是要处理的文件。在awk中,文件中的每一行,由字段分隔符分隔的每一项称为一个字段。通常,当不指定-F字段分隔符时,默认的字段分隔符是空格。2.shell脚本方法将所有awk命令插入到一个文件中,并使awk程序可执行,然后将awk命令解释器作为脚本的第一行,通过输入一次脚本名来调用。相当于shell脚本第一行:#!/bin/sh可以换成:#!/bin/awk3。将所有awk命令插入到一个单独的文件中,然后调用:awk-fawk-script-fileinput-file(s)其中-f选项加载awk-script-file中的awk脚本,input-file(s)同上。入口示例假设last-n5输出如下[root@www~]#last-n5#只取出前五行rootpts/1192.168.1.100TueFeb1011:21stillloggedinrootpts/1192.168.1.1002月10日星期二00:46-02:28(01:41)rootpts/1192.168.1.1002月9日星期一11:41-18:30(06:48)dmtsaipts/1192.168.1.100MonFeb911:41-11:41(00:00)roottty1FriSep514:09-14:10(00:01)如果只显示最后5个登录帐户#last-n5|awk'{print$1}'rootrootrootdmtsairootawk工作流程是这样的:读入一条以'n'换行符分隔的记录,然后按照指定的字段分隔符将记录分成字段,并填充字段,$0表示所有字段,$1表示第一个字段,$n表示第n个字段。默认的域分隔符是“空白键”或“[tab]键”,所以$1表示登录用户,$3表示登录用户ip,以此类推。如果只显示/etc/passwd的账号#cat/etc/passwd|awk-F':''{print$1}'rootdaemonbinsys如果只显示/etc/passwd的账号和该账号对应的shell,以及账户和shell的关系用tab键拆分#cat/etc/passwd|awk-F':''{print$1"\t"$7}'root/bin/bashdaemon/bin/shbin/bin/shsys/bin/sh如果只显示/etc/passwd的账号和该账号对应的shell,账号和shell用逗号隔开,所有行都加上列名name和shell,并且“blue,/bin/nosh"添加到最后一行。cat/etc/passwd|awk-F':''BEGIN{print"name,shell"}{print$1","$7}END{print"blue,/bin/nosh"}'name,shellroot,/bin/bashdaemon、/bin/shbin、/bin/shsys、/bin/sh....blue、/bin/noshawk工作流程是这样的:先执行BEGING,然后读取文件,读取文件以/n行分隔breakA记录,然后按照指定的域分隔符将记录划分为域,填写域,$0表示所有域,$1表示第一个域,$n表示第n个域,然后开始执行相应的模式action动作。然后开始读取第二条记录……直到读取完所有记录,最后执行END操作。在/etc/passwd中搜索具有根关键字的所有行#awk-F:'/root/'/etc/passwdroot:x:0:0:root:/root:/bin/bash这是一个示例pattern的使用,只有匹配到pattern的行(这里是root)才会执行action(如果没有指定action,默认输出每一行的内容)。搜索支持正则表达式,比如查找root开头:awk-F:'/^root/'/etc/passwd在/etc/passwd中搜索所有root关键字的行,并显示对应的shell#awk-F:'/root/{print$7}'/etc/passwd/bin/bash这里指定action{print$7}awk'length($0)>80{printNR}'myfile#这个命令行会显示更多文本myfile中超过80个字符的行号,这里用$0表示整条记录(行),内置变量NR没有使用符号'$'。#假设在UNIX下要检查用户的安全性,方法是检查/etc下的passwd文件,检查里面的passwd字段(第二个字段)是否为“*”,如果不是“*”,这意味着用户没有设置密码,显示这些用户名(第一个字段)。我们可以使用如下语句来实现:awk-F:'$2==""{printf("%snopassword!",$1)'/etc/passwd内置变量awk有很多内置变量可以设置环境信息,这些变量是可以改变的,下面给出一些最常用的变量。ARGC命令行参数个数ARGV命令行参数排列ENVIRON支持队列中的系统环境变量,使用FILENAMEawk浏览文件名FNR浏览文件的记录数FS设置输入字段分隔符,相当于命令行-F选项NF浏览记录域数(列)NR读取记录数(行)OFS输出域分隔符ORS输出记录分隔符RS控制记录分隔符另外,$0变量指的是整个记录。$1表示当前行的第一个字段,$2表示当前行的第二个字段,以此类推。awk'/api\.php/{print}'log_file#默认格式,mode为$0,即打印出整个awk'/api\.php/'log_file#连action部分都可以忽略,默认是printStatistics/etc/passwd:文件名,每行行号,每行列数,对应完整行内容:#awk-F':''{print"filename:"FILENAME",linenumber:“NR”,列:“NF”,行内容:“$0}”/etc/passwdfilename:/etc/passwd,linenumber:1,columns:7,linecontent:root:x:0:0:root:/root:/bin/bashfilename:/etc/passwd,linenumber:2,columns:7,linecontent:daemon:x:1:1:daemon:/usr/sbin:/bin/shfilename:/etc/passwd,linenumber:3,columns:7,linecontent:bin:x:2:2:bin:/bin:/bin/shfilename:/etc/passwd,linenumber:4,columns:7,linecontent:sys:x:3:3:sys:/dev:/bin/sh使用printf代替print可以让代码更简洁易读awk-F':''{printf("filename:%10s,linenumber:%s,columns:%s,linecontent:%s\n",FILENAME,NR,NF,$0)}'/etc/passwdprint和printfawk提供用于打印输出的print和printf函数。打印函数的参数可以是变量、值或字符串。字符串必须用双引号括起来,参数用逗号分隔。如果没有逗号,参数将被串联起来并且无法区分。在这里,逗号的作用和输出文件的分隔符一样,只不过后者是一个空格。printf函数,它的用法基本类似于C语言中的printf,可以格式化字符串,当输出比较复杂时,printf更易用,代码也更容易理解。head-10log_file|awk'{printf"%03d%s\n",NR,$1}'#"%03d%s\n"istheformat,whereNRreplaces%03withthreedigitsleading0,and$1replaces%s成为字符串001220.181.108.180002220.181.108.180003220.181.108.150004123.125.71.45005220.181.108.142006220.181.108.162007151.80.31.110008220.181.108.82009220.181.108.185010151.80.31.112awk编程变量和赋值除了awk的内置变量,awk还可以Customvariables.Thefollowingcountsthenumberofaccountsin/etc/passwdawk'{count++;print$0;}END{print"usercountis",count}'/etc/passwdroot:x:0:0:root:/root:/bin/bash...usercountis40countisacustomvariable.Thereisonlyoneprintinthepreviousaction{},infact,printisjustastatement,andaction{}canhavemultiplestatements,separatedby;.这里不初始化count,虽然默认是0,但是正确的做法是初始化为0:awk'BEGIN{count=0;print"[start]usercountis",count}{count=count+1;print$0;}END{print"[end]usercountis",count}'/etc/passwd[start]usercountis0root:x:0:0:root:/root:/bin/bash...[end]usercountis40统计文件夹中文件占用的字节数ls-l|awk'BEGIN{size=0;}{size=size+$5;}END{print"[end]sizeis",size}'[end]sizeis8657198#以兆字节显示ls-l|awk'BEGIN{size=0;}{size=size+$5;}END{print"[end]sizeis",size/1024/1024,"M"}'[end]sizeis8.25889MBEGIN和END是awk中的两个特殊表达式,BEGIN和END,都可以在pattern中使用(参考前面的awk语法),提供BEGIN和END的功能是给程序赋予初始状态,并在程序结束后进行一些清理工作。在BEGIN之后(在{}内)列出的任何操作都将在awk开始扫描输入之前执行,而在END之后列出的操作将在扫描完所有输入后执行。因此,通常用BEGIN显示变量和预置(初始化)变量,用END输出最终结果。awk>'BEGIN{FS=":";print"统计销售额";total=0}>{print$3;total=total+$3;}>END{printf"总销售额:%.2f",total}'#注意:>是shell提供的第二个提示符。shell程序awk语句和awk语言中如果要换行,需要在行尾加反斜杠#这里BEGIN预设了内部变量FS(字段分隔符)和自定义变量total,而扫描前显示输出行标题。END在扫描完成后打印出总数。条件语句if(表达式){语句;陈述;......}if(expression){statement;}else{statement2;}if(expression){statement1;}elseif(expression1){statement2;}else{statement3;}统计文件占用的字节数在文件夹中,并过滤大小为4096的文件(通常是文件夹):ls-l|awk'BEGIN{size=0;print"[start]sizeis",size}{if($5!=4096){size=size+$5;}}END{print"[end]sizeis",size/1024/1024,"M"}'[end]sizeis8.22339M循环语句awk中的循环语句也是借鉴了C语言,并支持while、do/while、for、break和continue。这些关键字的语义与C语言中的完全相同。awk-F':''BEGIN{count=0;}{name[count]=$1;count++;};END{for(i=0;i
