AWK介绍AWK是一个优秀的文本处理工具。它是最强大的数据处理引擎之一,不仅适用于Linux,而且适用于任何环境。这种编程和数据操作语言(其名称取自其创始人AlfredAho、PeterWeinberger和BrianKernighan的首字母缩写)的强大程度取决于一个人所拥有的知识。AWK提供了极其强大的功能:它可以执行样式加载、流程控制、数学运算符、过程控制语句,甚至内置变量和函数。它几乎具有完整语言的所有优点。AWK实际上确实有自己的语言:AWK编程语言,三位创建者已将其正式定义为“样式扫描和处理语言”。它允许您创建读取输入文件、排序数据、处理数据、对输入执行计算、生成报告和无数其他功能的短程序。使用方法awk'{pattern+action}'{filenames}虽然操作可能很复杂,但语法总是相同的,其中pattern表示AWK在数据中寻找什么,而action是当一个找到匹配顺序。花括号({})不需要在程序中始终如一地出现,但它们用于根据特定模式对指令序列进行分组。pattern是要表达的正则表达式,用斜杠括起来。awk语言最基本的功能是根据指定的规则浏览和提取文件或字符串中的信息。awk提取信息后,就可以进行其他文本操作了。完整的awk脚本通常用于格式化文本文件中的信息。通常,awk在一行中处理一个文件。awk接收文件的每一行,然后执行相应的命令来处理文本。调用awk命令行模式awk[-Ffield-separator]'commands'input-file(s)其中commands是真正的awk命令,[-Ffieldseparator]是可选的。输入文件是要处理的文件。在awk中,文件中的每一行,由字段分隔符分隔的每一项称为一个字段。通常,当不指定-F字段分隔符时,默认的字段分隔符是空格。shell脚本方式将所有awk命令插入到一个文件中,使awk程序可执行,然后将awk命令解释器作为脚本的第一行,通过输入一次脚本名调用。相当于shell脚本第一行:#!/bin/sh可以换成:#!/bin/awk将所有awk命令插入一个单独的文件,然后调用:awk-fawk-script-fileinput-file(s)其中,-f选项加载awk-script-file中的awk脚本,input-file(s)同上。入门示例(获取linux最近登录的五个用户的用户名)#下面是最近登录的五个用户的信息[root@localhost~]#last-n5rootpts/1192.168.1.1002月10日星期二11:21仍然记录intestpts/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)roottty1120.239.75.53FriSep514:09-14:10(00:01)#如果只有最后5显示帐户Name$last-n5|awk'{print$1}'roottestrootdmtsairoot#awk的工作流程是这样的:读入一条以'\n'换行符分隔的记录,然后按照指定的字段分隔符将记录分成字段,填入Domain,$0表示全部域,$1表示第一个域,$n表示第n个域。默认域分隔符是“空白键”或“[tab]键”,所以$1表示登录用户,$3表示登录用户ip,以此类推。入门示例(仅显示/etc/passwd帐户)$cat/etc/passwd|awk-F':''{print$1}'rootdaemonbinsys#这个是awk+action的例子,每一行都会执行action{print$1}。#-F指定字段分隔符为':'。#如果只显示/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显示account,account和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/nosh#awk的工作流程是这样的:先执行BEGING,然后读取文件,用/读取换行符n个字符,然后按照指定的字段分隔符将记录分成字段,并填充字段,$0表示所有字段,$1表示第一个字段,$n表示第n个字段,然后开始执行pattern对应的action行动。然后开始读取第二条记录……直到读取完所有记录,最后执行END操作。#在/etc/passwd中搜索所有带有root关键字的行$awk-F:'/root/'/etc/passwdroot:x:0:0:root:/root:/bin/bash#这是pattern的使用例如只有当行与模式匹配时才会执行action(这里是root)(如果没有指定action,则默认输出每一行的内容)。#搜索支持正则表达式,例如lookforroot:awk-F:'/^root/'/etc/passwd#搜索/etc/passwd中所有包含root关键字的行,并显示对应的shell$awk-F:'/root/{print$7}'/etc/passwd/bin/bash#这里指定了action{print$7}awk内置变量。awk有许多用于设置环境信息的内置变量。这些变量可以更改。一些常用的变量。$n#当前记录的第n个字段,比如n为1表示第一个字段,n为2表示第二个字段。$0#这个变量包含了执行时当前行的文本内容。ARGC#命令行参数的数量。ARGIND#当前文件在命令行中的位置(从0开始计数)。ARGV#包含命令行参数的数组。CONVFMT#数字转换格式(默认%.6g)。ENVIRON#环境变量关联数组。ERRNO#上次系统错误的描述。FIELDWIDTHS#字段宽度列表(空格分隔)。FILENAME#当前输入文件的名称。NR#表示记录数,对应执行时的当前行号。FNR#与NR相同,但相对于当前文件。FS#字段分隔符(默认为任意空格)。IGNORECASE#如果为true,则不区分大小写进行匹配。NF#表示字段数,对应当前执行时的字段数。print$NF允许输出一行中最后一个字段OFMT#number的格式(默认值为%.6g)。OFS#输出字段分隔符(默认为空格)。ORS#输出记录分隔符(默认为换行符)。RS#记录分隔符(默认为换行符)。RSTART#匹配函数匹配的字符串的第一个位置。RLENGTH#匹配函数匹配到的字符串的长度。SUBSEP#数组下标分隔符(默认值为34)。此外,$0变量指的是整个记录。$1代表当前行的第一个字段,$2代表当前行的第二个字段,以此类推。统计/etc/passwd:文件名,每行行号,每行列数,对应完整行内容:$awk-F':''{print"filename:"FILENAME",linenumber:"NR",列:“NF”,行内容:“$0}”/etc/passwdfilename:/etc/passwd,行号:1,列:7,行内容: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:%s,linenumber:%s,columns:%s,linecontent:%s\n",FILENAME,NR,NF,$0)}'/etc/passwdprint和printfawk提供用于打印输出的print和printf函数。打印函数的参数可以是变量、值或字符串。字符串必须用双引号括起来,参数用逗号分隔。如果没有逗号,参数将被串联起来并且无法区分。在这里,逗号的作用和输出文件的分隔符一样,只不过后者是一个空格。printf函数,它的用法基本类似于C语言中的printf,可以格式化字符串,当输出比较复杂时,printf更易用,代码也更容易理解。%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%awk编程变量和赋值除了awk的内置变量外,awk还可以自定义变量。下面统计/etc/passwd中的账号数awk'{count++;print$0;}END{print"usercountis",count}'/etc/passwdroot:x:0:0:root:/root:/bin/bash...用户数是40count是一个自定义变量。前面的action{}只有一个print,其实print只是一个语句,而action{}可以有多个语句,用;隔开。这里不初始化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如果在M中显示:ls-l|awk'BEGIN{size=0;}{size=size+$5;}END{print"[end]sizeis",size/1024/1024,"M"}'[end]sizeis8.25889M注意统计不包括文件夹的子目录。条件语句awk中的条件语句是从C语言中借用的,见如下语句:if(expression){statement;陈述;......}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语言中的语义完全相同。#forloopfor(variableinarray){statement}for(variable;condition;expression){statement}#whileloopwhile(expression){statement}#do...whileloopdo{statement}while(condition)#Other相关语句break:退出程序循环continue:进入下一个循环next:读取下一个输入行exit:退出主输入循环,进入END。如果没有END或者END中有exit语句,则退出脚本。数组因为awk中数组的下标可以是数字和字母,所以数组的下标通常被称为关键字(key)。值和键在内部存储在对键/值应用散列的表中。由于哈希不是按顺序存储的,当你显示数组的内容时,你会发现它们并没有按照你期望的顺序显示。和变量一样,数组在使用时会自动创建,awk也会自动判断其存储的是数字还是字符串。一般来说,awk中的数组用于从记录中收集信息,可以用来计算总和、统计单词、跟踪模板匹配的次数等。在/etc/passwd中显示帐户$awk-F':''BEGIN{count=0;}{name[count]=$1;count++;};END{for(i=0;i
