?!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
Table of Contents
awk是一U编E语aQ用于在linux/unix下对文本和数据进行处理。数据可以来自标准输入、一个或多个文gQ或其它命o的输出。它支持用户自定义函数和动态正则表辑ּ{先q功能,是linux/unix下的一个强大编E工兗它在命令行中用,但更多是作ؓ脚本来用。awk的处理文本和数据的方式是q样的,它逐行扫描文gQ从W一行到最后一行,L匚w的特定模式的行,q在q些行上q行你想要的操作。如果没有指定处理动作,则把匚w的行昄到标准输?屏幕)Q如果没有指定模式,则所有被操作所指定的行都被处理。awk分别代表其作者姓氏的W一个字母。因为它的作者是三个人,分别是Alfred Aho、Brian Kernighan、Peter Weinberger。gawk是awk的GNU版本Q它提供了Bell实验室和GNU的一些扩展。下面介l的awk是以GUN的gawkZ的,在linuxpȝ中已把awk链接到gawkQ所以下面全部以awkq行介绍?/P>
awk [options] 'script' var=value file(s)
awk [options] -f scriptfile var=value file(s)
指定输入文g折分隔符Qfs是一个字W串或者是一个正则表辑ּQ如-F:?/P>
赋g个用户定义变量?/P>
从脚本文件中dawk命o?/P>
对nnnD|内在限Ӟ-mf选项限制分配lnnn的最大块数目Q?mr选项限制记录的最大数目。这两个功能是Bell实验室版awk的扩展功能,在标准awk中不适用?/P>
在兼Ҏ(gu)式下q行awk。所以gawk的行为和标准的awk完全一P所有的awk扩展都被忽略?/P>
打印短的版权信息?/P>
打印全部awk选项和每个选项的简短说明?/P>
打印不能向传lunixq_UL的结构的警告?/P>
打印关于不能向传lunixq_UL的结构的警告?/P>
打开兼容模式。但有以下限Ӟ不识别:\x、函数关键字、func、换码序列以及当fs是一个空格时Q将新行作ؓ一个域分隔W;操作W?*?*=不能代替^和^=Qfflush无效?/P>
允许间隔正则表达式的使用Q参?grep中的Posix字符c?Q如括号表达式[[:alpha:]]?/P>
使用program-text作ؓ源代码,可与-f命oL?/P>
打印bug报告信息的版本?/P>
pattern {action} ? awk '/root/' testQ或$ awk '$3 < 100' test?/P>
两者是可选的Q如果没有模式,则action应用到全部记录,如果没有actionQ则输出匚w全部记录。默认情况下Q每一个输入行都是一条记录,但用户可通过RS变量指定不同的分隔符q行分隔?
模式可以是以下Q意一个:
/正则表达?Q用通配W的扩展集?/P>
关系表达式:可以用下面运符表中的关p运符q行操作Q可以是字符串或数字的比较,?2>%1选择W二个字D|W一个字D长的行?/P>
模式匚w表达式:用运符~(匚w)和~!(不匹??/P>
模式Q模式:指定一个行的范围。该语法不能包括BEGIN和END模式?/P>
BEGINQ让用户指定在第一条输入记录被处理之前所发生的动作,通常可在q里讄全局变量?/P>
ENDQ让用户在最后一条输入记录被d之后发生的动作?/P>
Table 1. awk的环境变?/B>
变量 | 描述 |
---|---|
$n | 当前记录的第n个字D,字段间由FS分隔?/TD> |
$0 | 完整的输入记录?/TD> |
ARGC | 命o行参数的数目?/TD> |
ARGIND | 命o行中当前文g的位|??开始算)?/TD> |
ARGV | 包含命o行参数的数组?/TD> |
CONVFMT | 数字转换格式(默认gؓ%.6g) |
ENVIRON | 环境变量兌数组?/TD> |
ERRNO | 最后一个系l错误的描述?/TD> |
FIELDWIDTHS | 字段宽度列表(用空格键分隔)?/TD> |
FILENAME | 当前文g名?/TD> |
FNR | 同NRQ但相对于当前文件?/TD> |
FS | 字段分隔W?默认是Q何空??/TD> |
IGNORECASE | 如果为真Q则q行忽略大小写的匚w?/TD> |
NF | 当前记录中的字段数?/TD> |
NR | 当前记录数?/TD> |
OFMT | 数字的输出格?默认值是%.6g)?/TD> |
OFS | 输出字段分隔W?默认值是一个空??/TD> |
ORS | 输出记录分隔W?默认值是一个换行符)?/TD> |
RLENGTH | 由match函数所匚w的字W串的长度?/TD> |
RS | 记录分隔W?默认是一个换行符)?/TD> |
RSTART | 由match函数所匚w的字W串的第一个位|?/TD> |
SUBSEP | 数组下标分隔W?默认值是\034)?/TD> |
awk把每一个以换行W结束的行称Z个记录?/P>
记录分隔W:默认的输入和输出的分隔符都是回RQ保存在内徏变量ORS和RS中?/P>
$0变量Q它指的是整条记录。如$ awk '{print $0}' test输出test文g中的所有记录?/P>
变量NRQ一个计数器Q每处理完一条记录,NR的值就增加1。如$ awk '{print NR,$0}' test输出test文g中所有记录,q在记录前显C录号?/P>
记录中每个单词称做“域”,默认情况下以I格或tab分隔。awk可跟t域的个敎ͼq在内徏变量NF中保存该倹{如$ awk '{print $1,$3}' test打印test文g中第一和第三个以空格分开的列(??/P>
一般通用的元字符集就不讲了,可参考我?A target=_top>Sed?A target=_top>Grep学习W记。以下几个是gawk专用的,不适合unix版本的awk?/P>
匚w一个单词开头或者末I字W串?/P>
匚w单词内的I字W串?/P>
匚w一个单词的开头的I字W串Q锚定开始?/P>
匚w一个单词的末尾的空字符Ԍ锚定末尾?/P>
匚w一个字母数字组成的单词?/P>
匚w一个非字母数字l成的单词?/P>
匚w字符串开头的一个空字符丌Ӏ?/P>
匚w字符串末一个空字符丌Ӏ?/P>
conditional expression1 ? expression2: expression3Q例如:$ awk '{max = {$1 > $3} ? $1: $3: print max}' test。如果第一个域大于W三个域Q?1p值给maxQ否?3p值给max?/P>
$ awk '$1 + $2 < 100' test。如果第一和第二个域相加大?00Q则打印q些行?/P>
$ awk '$1 > 5 && $2 < 10' test,如果W一个域大于5Qƈ且第二个域小?0Q则打印q些行?/P>
范围模板匚w从第一个模板的W一ơ出现到W二个模板的W一ơ出C间所有行。如果有一个模板没出现Q则匚w到开头或末尾。如$ awk '/root/,/mysql/' test显CrootW一ơ出现到mysqlW一ơ出C间的所有行?/P>
$ cat /etc/passwd | awk -F: '\
NF != 7{\
printf("line %d,does not have 7 fields:%s\n",NR,$0)}\
$1 !~ /[A-Za-z0-9]/{printf("line %d,non alpha and numeric user id:%d: %s\n,NR,$0)}\
$2 == "*" {printf("line %d, no password: %s\n",NR,$0)}'
$ awk '/^(no|so)/' test-----打印所有以模式no或so开头的行?/P>
$ awk '/^[ns]/{print $1}' test-----如果记录以n或s开_打印这个记录?/P>
$ awk '$1 ~/[0-9][0-9]$/(print $1}' test-----如果W一个域以两个数字结束就打印q个记录?/P>
$ awk '$1 == 100 || $2 < 50' test-----如果W一个或{于100或者第二个域小?0Q则打印该行?/P>
$ awk '$1 != 10' test-----如果W一个域不等?0打印该行?/P>
$ awk '/test/{print $1 + 10}' test-----如果记录包含正则表达式testQ则W一个域?0q打印出来?/P>
$ awk '{print ($1 > 5 ? "ok "$1: "error"$1)}' test-----如果W一个域大于5则打印问号后面的表达式|否则打印冒号后面的表辑ּ倹{?/P>
$ awk '/^root/,/^mysql/' test----打印以正则表辑ּroot开头的记录C正则表达式mysql开头的记录范围内的所有记录。如果找C个新的正则表辑ּroot开头的记录Q则l箋打印直到下一个以正则表达式mysql开头的记录为止Q或到文件末?/P>
在awk中,变量不需要定义就可以直接使用Q变量类型可以是数字或字W串?/P>
赋值格式:Variable = expressionQ如$ awk '$1 ~/test/{count = $2 + $3; print count}' test,上式的作用是,awk先扫描第一个域Q一旦test匚wQ就把第二个域的值加上第三个域的|q把l果赋值给变量countQ最后打印出来?/P>
awk可以在命令行中给变量赋|然后这个变量传输给awk脚本。如$ awk -F: -f awkscript month=4 year=2004 testQ上式的month和year都是自定义变量,分别被赋gؓ4?004。在awk脚本中,q些变量使用hp是在脚本中徏立的一栗注意,如果参数前面出现testQ那么在BEGIN语句中的变量׃能被使用?/P>
域变量也可被赋值和修改Q如$ awk '{$2 = 100 + $1; print }' test,上式表示Q如果第二个域不存在Qawk计表辑ּ100?1的|q将其赋值给$2Q如果第二个域存在,则用表达式的D?2原来的倹{再例如Q? awk '$1 == "root"{$1 ="test";print}' testQ如果第一个域的值是“root”,则把它赋gؓ“test”,注意Q字W串一定要用双引号?/P>
内徏变量的用。变量列表在前面已列出,现在举个例子说明一下? awk -F: '{IGNORECASE=1; $1 == "MARY"{print NR,$1,$2,$NF}'testQ把IGNORECASE设ؓ1代表忽略大小写,打印W一个域是mary的记录数、第一个域、第二个域和最后一个域?/P>
BEGIN模块后紧跟着动作块,q个动作块在awk处理M输入文g之前执行。所以它可以在没有Q何输入的情况下进行测试。它通常用来改变内徏变量的|如OFS,RS和FS{,以及打印标题。如Q? awk 'BEGIN{FS=":"; OFS="\t"; ORS="\n\n"}{print $1,$2,$3} test。上式表C,在处理输入文件以前,域分隔符(FS)被设为冒P输出文g分隔W?OFS)被设|ؓ制表W,输出记录分隔W?ORS)被设|ؓ两个换行W? awk 'BEGIN{print "TITLE TEST"}只打印标题?/P>
END不匹配Q何的输入文gQ但是执行动作块中的所有动作,它在整个输入文g处理完成后被执行。如$ awk 'END{print "The number of records is" NR}' testQ上式将打印所有被处理的记录数?/P>
awk可用shell的重定向W进行重定向输出Q如Q? awk '$1 = 100 {print $1 > "output_file" }' test。上式表C如果第一个域的值等?00Q则把它输出到output_file中。也可以?gt;>来重定向输出Q但不清I文Ӟ只做q加操作?/P>
输出重定向需用到getline函数。getline从标准输入、管道或者当前正在处理的文g之外的其他输入文件获得输入。它负责从输入获得下一行的内容QƈlNF,NR和FNR{内建变量赋倹{如果得C条记录,getline函数q回1Q如果到达文件的末尾p?Q如果出现错误,例如打开文gp|Q就q回-1。如Q?/P>
$ awk 'BEGIN{ "date" | getline d; print d}' test。执行linux的date命oQƈ通过道输出lgetlineQ然后再把输值给自定义变量dQƈ打印它?/P>
$ awk 'BEGIN{"date" | getline d; split(d,mon); print mon[2]}' test。执行shell的date命oQƈ通过道输出lgetlineQ然后getline从管道中dq将输入赋值给dQsplit函数把变量d转化成数lmonQ然后打印数lmon的第二个元素?/P>
$ awk 'BEGIN{while( "ls" | getline) print}'Q命令ls的输Z递给geline作ؓ输入Q@环getline从ls的输Zd一行,q把它打印到屏幕。这里没有输入文Ӟ因ؓBEGIN块在打开输入文g前执行,所以可以忽略输入文件?/P>
$ 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。在屏幕上打印”What is your name?",q等待用户应{。当一行输入完毕后Qgetline函数从终端接收该行输入,q把它储存在自定义变量name中。如果第一个域匚w变量name的|print函数p执行QEND块打印See you和name的倹{?/P>
$ awk 'BEGIN{while (getline < "/etc/passwd" > 0) lc++; print lc}'。awk逐行d文g/etc/passwd的内容,在到达文件末։Q计数器lc一直增加,当到末尾Ӟ打印l(f)c的倹{注意,如果文g不存在,getlineq回-1Q如果到达文件的末尾p?Q如果读C行,p?Q所以命? while (getline < "/etc/passwd")在文件不存在的情况下陷入无限@环,因ؓq回-1表示逻辑真?/P>
可以在awk中打开一个管道,且同一时刻只能有一个管道存在。通过close()可关闭管道。如Q? awk '{print $1, $2 | "sort" }' test END {close("sort")}。awd把print语句的输出通过道作ؓlinux命osort的输?END块执行关闭管道操作?/P>
system函数可以在awk中执行linux的命令。如Q? awk 'BEGIN{system("clear")'?/P>
fflush函数用以h输出~冲区,如果没有参数Q就h标准输出的缓冲区Q如果以I字W串为参敎ͼ如fflush(""),则刷新所有文件和道的输出缓冲区?/P>
awk中的条g语句是从C语言中借鉴q来的,可控制程序的程?/P>
格式Q? {if (expression){ statement; statement; ... } }
$ awk '{if ($1 <$2) print $2 "too high"}' test。如果第一个域于W二个域则打印?/P>
$ awk '{if ($1 < $2) {count++; print "ok"}}' test.如果W一个域于W二个域Q则count加一Qƈ打印ok?/P>
格式Q? {if (expression){ statement; statement; ... } else{ statement; statement; ... } }
$ awk '{if ($1 > 100) print $1 "bad" ; else print "ok"}' test。如?1大于100则打?1 bad,否则打印ok?/P>
$ awk '{if ($1 > 100){ count++; print $1} else {count--; print $2}' test。如?1大于100Q则count加一Qƈ打印$1Q否则count减一Qƈ打印$1?/P>
awk有三U@?while循环Qfor循环Qspecial for循环?/P>
$ awk '{ i = 1; while ( i <= NF ) { print NF,$i; i++}}' test。变量的初始gؓ1Q若i于可等于NF(记录中域的个?,则执行打印语句,且i增加1。直到i的值大于NF.
$ awk '{for (i = 1; i<NF; i++) print NF,$i}' test。作用同上?/P>
breadkcontinue语句。break用于在满x件的情况下蟩出@环;continue用于在满x件的情况下忽略后面的语句Q直接返回@环的端。如Q?/P>
{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}}
next语句从输入文件中d一行,然后从头开始执行awk脚本。如Q?/P>
{if ($1 ~/test/){next} else {print} }
exit语句用于l束awkE序Q但不会略过END块。退出状态ؓ0代表成功Q非零DC出错?/P>
awk中的数组的下标可以是数字和字母,UCؓ兌数组?/P>
用变量作为数l下标。如Q? awk {name[x++]=$2};END{for(i=0;i<NR;i++) print i,name[i]}' test。数lname中的下标是一个自定义变量xQawk初始化x的gؓ0Q在每次使用后增?。第二个域的D赋给name数组的各个元素。在END模块中,for循环被用于@环整个数l,从下标ؓ0的元素开始,打印那些存储在数l中的倹{因Z标是兛_字,所以它不一定从0开始,可以从Q何值开始?/P>
special for循环用于d兌数组中的元素。格式如下:
{for (item in arrayname){ print arrayname[item] } }$ awk '/^tom/{name[NR]=$1}; END{for(i in name){print name[i]}}' test。打印有值的数组元素。打印的序是随机的?
用字W串作ؓ下标。如Qcount["test"]
用域g为数l的下标。一U新的for循环方式Qfor (index_value in array) statement。如:$ awk '{count[$1]++} END{for(name in count) print name,count[name]}' test。该语句打?1中字W串出现的次数。它首先以第一个域作数lcount的下标,W一个域变化Q烦引就变化?/P>
delete函数用于删除数组元素。如Q? awk '{line[x++]=$1} END{for(x in line) delete(line[x])}' test。分配给数组line的是W一个域的|所有记录处理完成后Qspecial for循环删除每一个元素?/P>
sub函数匚w记录中最大、最靠左边的子字W串的正则表辑ּQƈ用替换字W串替换q些字符丌Ӏ如果没有指定目标字W串默认用整个记录。替换只发生在第一ơ匹配的时候。格式如下:
sub (regular expression, substitution string): sub (regular expression, substitution string, target string)
实例Q?/P>
$ awk '{ sub(/test/, "mytest"); print }' testfile $ awk '{ sub(/test/, "mytest"); $1}; print }' testfile
W一个例子在整个记录中匹配,替换只发生在W一ơ匹配发生的时候。如要在整个文g中进行匹配需要用到gsub
W二个例子在整个记录的第一个域中进行匹配,替换只发生在W一ơ匹配发生的时候?/P>
gsub函数作用如subQ但它在整个文中进行匹配。格式如下:
gsub (regular expression, substitution string) gsub (regular expression, substitution string, target string)
实例Q?/P>
$ awk '{ gsub(/test/, "mytest"); print }' testfile $ awk '{ gsub(/test/, "mytest"), $1 }; print }' testfile
W一个例子在整个文中匹配testQ匹配的都被替换成mytest?/P>
W二个例子在整个文的第一个域中匹配,所有匹配的都被替换成mytest?/P>
index函数q回子字W串W一ơ被匚w的位|,偏移量从位置1开始。格式如下:
index(string, substring)
实例Q?/P>
$ awk '{ print index("test", "mytest") }' testfile
实例q回test在mytest的位|,l果应该??/P>
length函数q回记录的字W数。格式如下:
length( string ) length
实例Q?/P>
$ awk '{ print length( "test" ) }' $ awk '{ print length }' testfile
W一个实例返回test字符串的长度?/P>
W二个实例返回testfile文g中第条记录的字符数?/P>
substr函数q回从位|?开始的子字W串Q如果指定长度超q实际长度,p回整个字W串。格式如下:
substr( string, starting position ) substr( string, starting position, length of string )
实例Q?/P>
$ awk '{ print substr( "hello world", 7,11 ) }'
上例截取了world子字W串?/P>
match函数q回在字W串中正则表辑ּ位置的烦引,如果找不到指定的正则表达式则q回0。match函数会设|内建变量RSTART为字W串中子字符串的开始位|,RLENGTH为到子字W串末尾的字W个数。substr可利于这些变量来截取字符丌Ӏ函数格式如下:
match( string, regular expression )
实例Q?/P>
$ awk '{start=match("this is a test",/[a-z]+$/); print start}' $ awk '{start=match("this is a test",/[a-z]+$/); print start, RSTART, RLENGTH }'
W一个实例打Cq箋写字符l尾的开始位|,q里?1?/P>
W二个实例还打印RSTART和RLENGTH变量Q这里是11(start)Q?1(RSTART)Q?(RLENGTH)?/P>
toupper和tolower函数可用于字W串大小间的转换Q该功能只在gawk中有效。格式如下:
toupper( string ) tolower( string )
实例Q?/P>
$ awk '{ print toupper("test"), tolower("TEST") }'
split函数可按l定的分隔符把字W串分割Z个数l。如果分隔符没提供,则按当前FSD行分剌Ӏ格式如下:
split( string, array, field separator ) split( string, array )
实例Q?/P>
$ awk '{ split( "20:18:00", time, ":" ); print time[2] }'
上例把时间按冒号分割到time数组内,q显C第二个数组元素18?/P>
systime函数q回?970q??日开始到当前旉(不计闰年)的整U数。格式如下:
systime()
实例Q?/P>
$ awk '{ now = systime(); print now }'
strftime函数使用C库中的strftime函数格式化时间。格式如下:
systime( [format specification][,timestamp] )
Table 3. 日期和时间格式说明符
格式 | 描述 |
---|---|
%a | 星期几的~写(Sun) |
%A | 星期几的完整写法(Sunday) |
%b | 月名的羃?Oct) |
%B | 月名的完整写?October) |
%c | 本地日期和时?/TD> |
%d | 十进制日?/TD> |
%D | 日期 08/20/99 |
%e | 日期Q如果只有一位会补上一个空?/TD> |
%H | 用十q制表示24时格式的小?/TD> |
%I | 用十q制表示12时格式的小?/TD> |
%j | ??日v一q中的第几天 |
%m | 十进制表C的月䆾 |
%M | 十进制表C的分钟 |
%p | 12时表示?AM/PM) |
%S | 十进制表C的U?/TD> |
%U | 十进制表C的一q中的第几个星期(星期天作Z个星期的开? |
%w | 十进制表C的星期?星期天是0) |
%W | 十进制表C的一q中的第几个星期(星期一作ؓ一个星期的开? |
%x | 重新讄本地日期(08/20/99) |
%X | 重新讄本地旉(12Q?0Q?0) |
%y | 两位数字表示的年(99) |
%Y | 当前月䆾 |
%Z | 时区(PDT) |
%% | 癑ֈ?%) |
实例Q?/P>
$ awk '{ now=strftime( "%D", systime() ); print now }' $ awk '{ now=strftime("%m/%d/%y"); print now }'