1.awk简介
awk是一种编程语言,用于在linux/unix下对文本和数据进行处理。数据可以来自标准输入、一个或多个文件,或其它命令的输出。它支持用户自定义函数和动态正则表达式等先进功能,是linux/unix下的一个强悍编程工具。它在命令行中使用,但更多是作为脚本来使用。awk的处理文本和数据的方法是这样的,它逐行扫描文件linux中awk命令,从第一行到最后一行linux中awk命令,找寻匹配的特定模式的行,并在那些行上进行你想要的操作。若果没有指定处理动作,则把匹配的行显示到标准输出(屏幕),假如没有指定模式,则所有被操作所指定的行都被处理。awk分别代表其作者姓氏的第一个字母。由于它的作者是三个人,分别是AlfredAho、BrianKernighan、PeterWeinberger。gawk是awk的GNU版本,它提供了Bell实验室和GNU的一些扩充。下边介绍的awk是以GUN的gawk为例的,在linux系统中已把awk链接到gawk,所以下边全部以awk进行介绍。
2.awk命令格式和选项
2.1.awk的句型有两种方式
awk [options] 'script' var=value file(s) awk [options] -f scriptfile var=value file(s)
2.2.命令选项
-F fs or --field-separator fs 指定输入文件折分隔符,fs是一个字符串或者是一个正则表达式,如-F:。 -v var=value or --asign var=value 赋值一个用户定义变量。 -f scripfile or --file scriptfile 从脚本文件中读取awk命令。 -mf nnn and -mr nnn 对nnn值设置内在限制,-mf选项限制分配给nnn的最大块数目;-mr选项限制记录的最大数目。这两个功能是Bell实验室版awk的扩展功能,在标准awk中不适用。 -W compact or --compat, -W traditional or --traditional 在兼容模式下运行awk。所以gawk的行为和标准的awk完全一样,所有的awk扩展都被忽略。 -W copyleft or --copyleft, -W copyright or --copyright 打印简短的版权信息。 -W help or --help, -W usage or --usage 打印全部awk选项和每个选项的简短说明。 -W lint or --lint 打印不能向传统unix平台移植的结构的警告。 -W lint-old or --lint-old 打印关于不能向传统unix平台移植的结构的警告。 -W posix 打开兼容模式。但有以下限制,不识别:x、函数关键字、func、换码序列以及当fs是一个空格时,将新行作为一个域分隔符;操作符**和**=不能代替^和^=;fflush无效。 -W re-interval or --re-inerval 允许间隔正则表达式的使用,参考(grep中的Posix字符类),如括号表达式[[:alpha:]]。 -W source program-text or --source program-text 使用program-text作为源代码,可与-f命令混用。 -W version or --version 打印bug报告信息的版本。
3.模式和操作
awk脚本是由模式和操作组成的:
pattern {action} 如$ awk '/root/' test,或$ awk '$3 < 100' test。
二者是可选的,假如没有模式,则action应用到全部记录,假如没有action,则输出匹配全部记录。默认情况下,每一个输入行都是一条记录,但用户可通过RS变量指定不同的分隔符进行分隔。
3.1.模式
模式可以是以下任意一个:
/正则表达式/:使用通配符的扩展集。 关系表达式:可以用下面运算符表中的关系运算符进行操作,可以是字符串或数字的比较,如$2>%1选择第二个字段比第一个字段长的行。 模式匹配表达式:用运算符~(匹配)和~!(不匹配)。 模式,模式:指定一个行的范围。该语法不能包括BEGIN和END模式。 BEGIN:让用户指定在第一条输入记录被处理之前所发生的动作,通常可在这里设置全局变量。 END:让用户在最后一条输入记录被读取之后发生的动作。
3.2.操作
操作由一人或多个命令、函数、表达式组成,之间由换行符或分号隔开,并坐落大括弧内。主要有四部分:
4.awk的环境变量
Table1.awk的环境变量
5.awk运算符
Table2.运算符
6.记录和域
6.1.记录
awk把每一个以换行符结束的行称为一个记录。
记录分隔符:默认的输入和输出的分隔符都是回车,保存在内建变量ORS和RS中。
$0变量:它指的是整条记录。如
$ awk '{print $0}' test
将输出test文件中的所有记录。
变量NR:一个计数器,每处理完一条记录,NR的值就降低1。如$awk'{printNR,$0}'test将输出test文件中所有记录,并在记录前显示记录号。
6.2.域
记录中每位词组称做“域”,默认情况下以空格或tab分隔。awk可跟踪域的个数,并在内建变量NF中保存该值。如$awk'{print$1,$3}'test将复印test文件中第一和第三个以空格分开的列(域)。
6.3.域分隔符
内建变量FS保存输入域分隔符的值RAR FOR LINUX,默认是空格或tab。我们可以通过-F命令行选项更改FS的值。如
$ awk -F: '{print $1,$5}' test
将复印以逗号为分隔符的第一,第五列的内容。
可以同时使用多个域分隔符,这时应当把分隔符写成放在方括弧中,如
$awk -F'[:t]' '{print $1,$3}' test
表示以空格、冒号和tab作为分隔符。
输出域的分隔符默认是一个空格,保存在OFS中。如
$ awk -F: '{print $1,$5}' test
$1和$5间的冒号就是OFS的值。
7.gawk专用正则表达式元字符
通常通用的元字符集就不讲了,可参考我的Sed和Grep学习笔记。以下几个是gawk专用的,不适宜unix版本的awk。
Y 匹配一个单词开头或者末尾的空字符串。 B 匹配单词内的空字符串。 匹配一个单词的末尾的空字符串,锚定末尾。 w 匹配一个字母数字组成的单词。 W 匹配一个非字母数字组成的单词。 ‘ 匹配字符串开头的一个空字符串。 ' 匹配字符串末尾的一个空字符串。
8.POSIX字符集
可参考我的Grep学习笔记
9.匹配操作符(~)
拿来在记录或则域内匹配正则表达式。如$awk'$1~/^root/'test将显示test文件第一列中以root开头的行。
10.比较表达式
conditionalexpression1expression2:expression3,比如:
$ awk '{max = {$1 > $3} $1: $3: print max}' test
假如第一个域小于第三个域,$1就形参给max,否则$3就形参给max。
$awk'$1+$2<100'test。假如第一和第二个域相加强于100,则复印那些行。
$awk'$1>5&&$2<10'test,假如第一个域小于5,但是第二个域大于10,则复印那些行。
11.范围模板
范围模板匹配从第一个模板的第一次出现到第二个模板的第一次出现之间所有行。假如有一个模板没出现,则匹配到开头或末尾。如$awk'/root/,/mysql/'test将显示root第一次出现到mysql第一次出现之间的所有行。
12.一个验证passwd文件有效性的事例
$ cat /etc/passwd | awk -F: ' NF != 7{ printf("line %d,does not have 7 fields:%sn",NR,$0)} $1 !~ /[A-Za-z0-9]/{printf("line %d,non alpha and numeric user id:%d: %sn,NR,$0)} $2 == "*" {printf("line %d, no password: %sn",NR,$0)}'
剖析:
cat把结果输出给awk,awk把域之间的分隔符设为逗号。
假如域的数目(NF)不等于7,就执行下边的程序。
printf复印字符串"linedoesnothave7fields",并显示该条记录。
假如第一个域没有包含任何字母和数字,printf复印“noalphaandnumericuserid",并显示记录数和记录。
假如第二个域是一个星号,就复印字符串“nopasswd”,紧跟随显示记录数和记录本身。
13.几个实例
$ awk '/^(no|so)/' test-----打印所有以模式no或so开头的行。 $ awk '/^[ns]/{print $1}' test-----如果记录以n或s开头,就打印这个记录。 $ awk '$1 ~/[0-9][0-9]$/(print $1}' test-----如果第一个域以两个数字结束就打印这个记录。 $ awk '$1 == 100 || $2 5 "ok "$1: "error"$1)}' test-----如果第一个域大于5则打印问号后面的表达式值,否则打印冒号后面的表达式值。 $ awk '/^root/,/^mysql/' test----打印以正则表达式root开头的记录到以正则表达式mysql开头的记录范围内的所有记录。如果找到一个新的正则表达式root开头的记录,则继续打印直到下一个以正则表达式mysql开头的记录为止,或到文件末尾。
14.awk编程
14.1.变量
$ awk '$1 ~/test/{count = $2 + $3; print count}' test
$ awk -F: -f awkscript month=4 year=2004 test
$ awk '{$2 = 100 + $1; print }' test
$ awk '$1 == "root"{$1 ="test";print}' test
$ awk -F: '{IGNORECASE=1; $1 == "MARY"{print NR,$1,$2,$NF}'test
14.2.BEGIN模块
BEGIN模块后紧跟随动作块,这个动作块在awk处理任何输入文件之前执行。所以它可以在没有任何输入的情况下进行测试。它一般拿来改变内建变量的值linux qq,如OFS,RS和FS等,以及复印标题。如:
$ awk 'BEGIN{FS=":"; OFS="t"; ORS="nn"}{print $1,$2,$3} test。
上式表示,在处理输入文件先前,域分隔符(FS)被设为逗号,输出文件分隔符(OFS)被设置为制表符,输出记录分隔符(ORS)被设置为两个换行符。$awk'BEGIN{print"TITLETEST"}只复印标题。
14.3.END模块
END不匹配任何的输入文件,并且执行动作块中的所有动作,它在整个输入文件处理完成后被执行。如
$ awk 'END{print "The number of records is" NR}' test
上式将复印所有被处理的记录数。
14.4.重定向和管线
$ awk '$1 = 100 {print $1 > "output_file" }' test。
$ awk 'BEGIN{ "date" | getline d; print d}' test。
$ awk 'BEGIN{"date" | getline d; split(d,mon); print mon[2]}' test。
$ 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 you," name "."} test。
$ awk 'BEGIN{while (getline 0) lc++; print lc}'。
$ awk 'BEGIN{system("clear")'。
14.5.条件句子
awk中的条件句子是从C语言中借鉴过来的,可控制程序的流程。
14.5.1.if句子
格式: {if (expression){ statement; statement; ... } }
$awk'{if($1100)print$1"bad";elseprint"ok"}'test。
假如$1小于100则复印$1bad,否则复印ok。
$awk'{if($1>100){count++;print$1}else{count--;print$2}'test
假如$1小于100,则count加一,并复印$1,否则count减一,并复印$1。
14.5.3.if/elseelseif句子,用于多重判别。
格式: {if (expression){ statement; statement; ... } else if (expression){ statement; statement; ... } else if (expression){ statement; statement; ... } else { statement; statement; ... } }
14.6.循环
$ awk '{ i = 1; while ( i <= NF ) { print NF,$i; i++}}' test
$ awk '{for (i = 1; i<NF; i++) print NF,$i}' test
{for ( x=3; x<=NF; x++) if ($x<0){print "Bottomed out!"; break}} {for ( x=3; x<=NF; x++) if ($x==0){print "Get next item"; continue}}
{if ($1 ~/test/){next} else {print} }
14.7.链表
awk中的字段的下标可以是数字和字母,称为关联链表。
14.7.1.下标与关联链表
$ awk {name[x++]=$2};END{for(i=0;i<NR;i++) print i,name[i]}' test
{for (item in arrayname){ print arrayname[item] } }
$awk'/^tom/{name[NR]=$1};END{for(iinname){printname[i]}}'test。
$ awk '{count[$1]++} END{for(name in count) print name,count[name]}' test
$ awk '{line[x++]=$1} END{for(x in line) delete(line[x])}' test
14.8.awk的内建函数
14.8.1.字符串函数
sub (regular expression, substitution string): sub (regular expression, substitution string, target string)
$ awk '{ sub(/test/, "mytest"); print }' testfile $ awk '{ sub(/test/, "mytest"); $1}; print }' testfile
gsub (regular expression, substitution string) gsub (regular expression, substitution string, target string)
$ awk '{ gsub(/test/, "mytest"); print }' testfile $ awk '{ gsub(/test/, "mytest"), $1 }; print }' testfile
index(string, substring)
$ awk '{ print index("test", "mytest") }' testfile
length( string ) length
$ awk '{ print length( "test" ) }' $ awk '{ print length }' testfile
substr( string, starting position ) substr( string, starting position, length of string )
$ awk '{ print substr( "hello world", 7,11 ) }'
match( string, regular expression )
$ awk '{start=match("this is a test",/[a-z]+$/); print start}' $ awk '{start=match("this is a test",/[a-z]+$/); print start, RSTART, RLENGTH }'
toupper( string ) tolower( string )
$ awk '{ print toupper("test"), tolower("TEST") }'
split( string, array, field separator ) split( string, array )
$ awk '{ split( "20:18:00", time, ":" ); print time[2] }'
14.8.2.时间函数
systime()
$ awk '{ now = systime(); print now }'
systime( [format specification][,timestamp] )
$ awk '{ now=strftime( "%D", systime() ); print now }' $ awk '{ now=strftime("%m/%d/%y"); print now }'
14.8.3.内建语文函数
Table4.
14.8.4.自定义函数
在awk中还可自定义函数,格式如下:
function name ( parameter, parameter, parameter, ... ) { statements return expression # the return statement and expression are optional }
15.How-to