4.awk的三种调用方式:
awk ‘pattern{action}’ filename1,filename2
awk –f myscript.awk filename1,filename2
#!/bin/nawk –f … … 执行:myscript.awk filename 特别注意事项: ---------------------------------------------------------------------------------------------------------------------- A.从window拷贝语法句到Unix中,行结尾可能有不识别的字符会导致语法错误 B.写script文件时,BEGIN或END后必须紧跟{ C.所有action语句必须放在{ }中,否则提示语法错误。例如不可直接写print D.单独的赋值或pattern条件句没有{ }则默认print $0;例如{ }外面的i=1 E.if条件块必须放在action中,也就是必须要有{ }来包含 F.条件的判断“相等”须用= =,而不是=(赋值);例如,if($1= =100) G.输出多列须用“,”(逗号)隔开;for循环中间隔符为“;”而不是“,” 实例演练:(filename为以下文件,注意:第二列用“-”隔开而非空格,以避免与FS冲突) ID Name Age City Country Tel Salary Children 1001 Steven 25 NY U.S.A +01-02-323222 $4900 2 1002 Huang-Yu 30 BJ CHN +86-10-36789966 ¥6000 1 1003 Fish-Mad 27 SG SG +65-67456632 $3000 3 1004 Vale-Kiss 46 LD ENG +44-20-87634321 $6280 3 ----------------------------------------------------------------------------------------------------------------------以下分基础实例:1.无pattern 的action实例 2.有pattern的action实例 3.BEGIN,END,FS,OFS实例 4.if else; for while循环实例 5.数学运算与字符串操作实例 高级实例:6.数组与关联数组运用实例 7.多文件运用NR FNR实例 8.输出重定向和getline实例 1 基 础 篇 1.无pattern的action实例 a.awk ‘{print NR $1 $NF}’ data.txt 打印行号,第一列和最后一列,中间无分隔符 b.awk ‘{print $1,$NF}’ data.txt 打印第一列和最后一列,并且中间有分隔符 c.awk ‘{print $0,$NF+10}’ data.txt 打印整行,并打印 最后一行加上10的结果 2.有pattern的action实例 a.awk ‘/[0-9]/’ data.txt 打印记录中任意列包含数字0-9的行 b.awk ‘/01/||/02/’ data.txt 打印包含01或者02的行 c.awk ‘/01/,/02/’ data.txt 打印既包含01又包含02的行;等同awk ‘/01/&&/02’ d.awk ‘$1= =1001{print $2}’ data.txt 打印符合第一列等于1001的第二列 e.awk ‘$2= =”Steven”{print}’data.txt 打印符合第二列等于Steven的那些行 f.awk ‘$3>20&&$3<30’ data.txt 打印第三列在20到30之间的那些行 g.nawk ‘$3*$NF<100’ data.txt 打印第三列和最后一列乘积小于100的那些行 h.awk ‘$6~/01/{print $2}’ data.txt 打印符合仅仅第六列里包含01那些行的第二列 i.awk ‘NR>3{print $1,$2}’ data.txt 从第四行才开始打印第一列和第二列 3.有BEGIN、END并包含FS、OFS的实例 a.awk –F”+” ‘{print $1}’ data.txt 按+为分隔符来分隔列,并打印第一列 b.nawk –F’[+t$]’ ‘{print $6,$7,$8,$9}’data.txt 按+或t或$都可作分隔符,并打印指定列 c.nawk ‘BEGIN{FS=”[t+$]”}{print $6,$8,$9}’data.txt 按+,t,$(顺序无所谓)为分割符,并打印指定列 d.nawk ‘BEGIN{FS=”[t+$]”;OFS=”%”}{print $6,$7,$8,$9}’ data.txt 按+,t,$为分割符,用%作输出分隔符打印指定列 e.nawk –F‘[ [ ] ]’ ‘{print $1}’ data.txt 按 [ 或 ] 为分隔符,并打印第一列 f.nawk –F‘[ ][ ]’ ‘{print $1}’ data.txt 同上,按[ 或 ] 为分隔符,并打印第一列 关于-F和BEGIN内的FS定义特别注意如下: A.-F参数后紧跟单个分隔符,则用双引号“”,例如 –F”+” B.-F参数后紧跟多个分隔符,则用单引号‘ ’并用[ ],中间顺序无所谓,例如-F’[+$]’ C.BEGIN中的FS无论是单个还是多个分隔,均用双引号“”,多个则需加[ ] 例如:nawk ‘BEGIN{FS=”[t+$]”}{print $6,$8,$9}’data.txt D.BEGIN中若同时有FS和OFS,则建议中间用分号“;”来分隔开,否则提示出错 例如:nawk ‘BEGIN{FS=”[t+$]”;OFS=”%”}{print $6,$7,$8,$9}’ data.txt E.半方括号[ ]也可以作为分隔符,顺序无所谓。例如:-F‘[[]]’ 或 –F‘[][]’ F.在用多个分隔符的时候,为避免语法错误或想得到正确的结果,最好用nawk 4.条件if else和for while循环实例 a.nawk ‘{print($3>25 ? $2“ Old” : $2“ Young”)}’ data.txt 若第三列大于25就打印某某Old;否则打印某某Young b.awk ‘{if($1>1002)print $2; else print $3}’ data.txt 若第二列大于1002就打印第二列,否则打印第三列 c.awk ‘NR>1{if($3<30)print$2;else if($3<40) print$2”m”;else exit;}END{print 10}’data.txt 从第二行开始判断第三列的值,如果小于30就打印$2,如果大于30而又小于 2 40,打印$2并后跟m,若是都不符合就退出处理行,但是END后的操作仍执行 d.awk ‘BEGIN{ORS=””}{for(i=1;i<nf-2;i++) print="" $i”t”}{print="" “n”}’="" data.txt 打印出每行的前面几列,最后几列不打印。特别注意:默认情况下,print每执行一次时,另起一行打印。因此为避免每打印一列就重新一行,设置ORS为空,但是在每打印完符合条件的所有列后,需要手工换行(循环外的print起此作用)。 e.awk ‘BEGIN{ORS=””}{i=1; while(i<nf-2){print $i”t”;="" i++}}{print="" “n”}’="" data.txt 功能同上,打印出每行的前面几列,最后几列不打印。 5.数学运算和字符串操作实例 a.nawk ‘{print 2^5+sin(2.1)+int(0.9)}’ data.txt 在每一行都打印运算值(32.8632) b.awk ‘END{print length(“How are you?”)}’ data.txt 打印出字符串的长度(12) c.awk ‘END{print index(“How are you?”,”you”)}’ data.txt 返回you在字符串中的开始位置(9) d.nawk ‘{gsub(/ $/,””);print $0}’ data.txt 把每行的$符号用空替掉,并打印行 e.awk ‘END{print substr(“How are you?”,9,3)}’ data.txt 从字符串的第九个位置开始截出后面3个长度的子字符串 f.nawk ‘{print toupper($2), tolower($2)}’ data.txt 分别打印第二列大写和小写 g.nawk ‘END{print match(“How are you you?”,/you/),RSTART,RLENGTH}’ data.txt 打印you在字符串中第一个匹配的位置以及长度(9,9,3) h.nawk ‘END{str=”How are you doing?”;sub(/o/,”0”,str);print str}’ data.txt 将字符串变量指定字符中第一个符合含有o的用0替换调 特别注意:sub函数的第三个参数不可直接用字符串,而必须用字符串变量。 i.awk ‘END{print split(“Jan,Feb,Mar,Apr,May”,mymonths,”,”),mymonths[2]}’ data.txt 将字符串用第三个参数分隔符号进行分隔,把分隔的各个元素放在第二个参数的数组中,函数返回分隔得到的元素数目。结果:(5,Feb) 高 级 篇 6.数组与关联数组(a[1],a[$1] a[$0],a[b]) a.awk ‘{for(i=1;i<nf;i++) {a=$i; print a}}’ data.txt 把文件每一列按行打印 b.awk ‘{a[$1]=$2}END{for(x in a) print a[x]}’ data.txt 数组a关联到第一列,并将第二列值赋给a,最后打印a中的所有内容。注意:但不是顺序打印。for中的x是随意变量,awk自动确定。 c.awk ‘{b=$1;a[$1]=$2;i++}END{for(j=1;j<i;j++) print="" b[j],a[b[j]]}’="" data.txt 实现从第二行开始打印每一行的第一列和第二列的功能。 注意:i从0开始取值,而j从1开始。a为关联数组,b为顺序数组。 7.多输入文件和NR、FNR的实例 a. awk ‘BEGIN{OFS=FS=”:”} NR==FNR{a[$1]=$2} NR>FNR{$2=a[$1];print}’ /etc/shadow /etc/passwd 该语句中第一个模式匹配到第一个输入文件shadow,第二个模式匹配到第二个输入文件passwd,并使用关联数组,实现不同文件关联列的其他列值相互替换。 3 A.awk对多输入文件的执行顺序是,先将代码作用于第一个文件(一行行读入),然后该重复的代码又作用于第二个文件,再作用于第三个文件。 B.awk对多输入文件的执行顺序产生了行序号的问题。当第一个文件执行完,下次读入第二个文件,那么第二个文件的第一行怎么算呢?如果又计为1的话,那不就两个1了么?(因为第一个文件也有第一行)。这就是NR和FNR的问题。 NR :全局行数(第二个文件的第一行接着第一个文件尾行数顺序计数) FNR:当前文件自身的行数(不考虑前几个输入文件的自身行数及总数) 例如:data1.txt中有40行,data2.txt中有50行,那么awk ‘{}’ data1.txt data2.txt NR 的值依次为:1,2……40,41,42……90 FNR的值依次为:1,2……40, 1, 2……50 8.重定向输出和特别函数getline实例 a.awk ‘{print FILENAME,$0}’ data1.txt data2.txt >data_all.txt 把第一个文件和第二个文件合并到data_all.txt中,新文件第一列为原始文件名,后面列为原始文件内容。 b.awk ‘$1!=fd{close(fd);fd=$1} {print substr($0,index($0,“ ”)+1)>$1}’ data_all.txt 把合并后的新文件data.txt重新拆开成原来的两个子文件,依照新文件的第一列来产生新文件名。生成一个完整子文件后,关闭之;再生成下一个子文件。 A.getline从整体上来说,应这么理解它的用法: 当其左右无重定向符 | 或 < 时,getline作用于当前文件,读入当前文件的第一行给其后跟的变量 var 或$0(无变量);应该注意到,由于awk在处理getline之前已经读入了一行,所以getline得到的返回结果是隔行的。 当其左右有重定向符 | 或 < 时,getline则作用于定向输入文件,由于该文件是刚打开,并没有被awk读入一行,只是getline读入,那么getline返回的是该文件的第一行,而不是隔行。 B.getline用法大致可分为三大类(每大类又分两小类),即总共有6种用法。代码如下: nawk ‘BEGIN{“cat data.txt”|getline d; print d}’ data2.txt nawk ‘BEGIN{“cat data.txt”|getline; print $0}’ data2.txt nawk ‘BEGIN{getline d < “data.txt”; print d}’ data2.txt nawk ‘BEGIN{getline < “data.txt”; print $0}’ data2.txt 以上四行代码均实现“只打印data.txt文件的第一行”(若打印全部行,用循环) eg. nawk ‘BEGIN{FS=”:”;while(getline<”/etc/passwd”>0){print $1}}’ data.txt nawk ‘{getline d; print d”#”$3}’ data.txt awk首先读入第一行,接着处理getline函数,然后把下一行指定给变量d,再先打印d,由于d后面有换行符,所以后面紧跟的#会覆盖d,后面的$3同样也会覆盖d。 nawk ‘{getline; print $0”#”$3}’ data.txt awk首先读入第一行接着处理getline函数,然后把下一行指定给$0,现在的$0已经是下一行内容,后面的#和$3(从$0中取)会覆盖$0的内容。 c.nawk ‘BEGIN{system(“echo ”input your name:” ”);getline var; print “nYour name is”,d,”n”}’ 系统提示输入名字,然后将输入的名字打印出来。特别注意:该awk语句后没有输入文件名,而是利用键盘输入作为文件名。 4 经 典 实 例 1.问题描述 有如下银行帐单部分文本, 200000000000007|shi yan city qi pei bu 202111320000018|hospital 200000000000007|shiyan city renmen road qi bei bu 201602520002941|middle school 200000000000007|mingfeng road qi pei 201602120000113|zhuanghuang factory 201602320000115|liangyou factory 要求:将第一列中重复的合并为一行,其第二列填入最长地址的那列 得到的结果应为: 200000000000007|shiyan city renmen road qi bei bu 202111320000018|hospital 201602520002941|middle school 201602120000113|zhuanghuang factory 201602320000115|liangyou factory 代码:(假设下面代码在文件myawk..sh中) #!/usr/bin/nawk -f BEGIN{FS=OFS="|"; i=1;} { if(a[$1]==0){b=$1;a[$1]=$2;i++} if(length(a[$1])<length($2)){a[$1]=$2} } END{for(j=1;j<i;j++) print="" b[j],a[b[j]] } 执行:myawk.sh data.txt 比较代码:(实现不全) awk 'BEGIN{FS=OFS="|"} !(length(a[$1])>length($2)){a[$1]=$2} END{for(i in a)print i,a}' data.txt 解释:此例中,用了两个数组,a用来与$1关联,b用来顺序记录,使得在最后打印时是完全按照$1顺序打印。条件句首先判断数组元素是否是第一次写入,若非,则比较当前$2值和以前储存的值长度。 功能不全代码不能顺序打印。当$1有重复,而$2长度第一次、第二次、第三次是以递减的方式时,该代码应用得较好。但是,当$2各次得到的长度不确定时,代码不能实现上述功能。例如:本例中第5行的第二列若比第3行的第二列长度长时,功能不全代码就不能实现要求。 5 2.问题描述: 有两个文件如下: data1文件内容: 1 0.5 100 10 15 36.5 data2文件内容: 50 10 19 3.2 1 5 要求:得到一个新的文件,内容是data1和data2对应的列数字相加的和,新文件内容: 51 10.5 119 13.2 16 41.5 代码:(假设下面代码在文件myawk..sh中) #!/usr/bin/nawk -f { for(i=1;i<=NF;i++) a=$i; getline < “data2.txt” for(j=1;j<nf;j++) printf="" $j+a[j]="" “t” printf $NF+a[NF]“n” } 执行:myawk.sh data1.txt 解释: 上述代码用到了getline同时读入第二个文件的行内容并存入到$0中,最后用printf来实现相加后的打印。注意后面同时紧跟打印了t和n,以用来列之间的分隔和行之间的分隔。此外,也可以用print来实现,但是print每执行完一次都要换行,(当然可以用OFS来进一步处理)。 实际上也可以用另外一种办法来实现,就是用NR、FNR比较,然后分别将两个文件赋值给不同的数组,然后相加。当然代码就没有上述代码简练。 3.问题描述 有两个如下文件: data2.txt 文件内容如下: 01 1111 AAA WW001 $$$$ 1000.00 02 2222 BBB GG001 %%%% 2000.00 03 3333 CCC JJ001 **** 3000.00 04 4444 DDD FF002 &&&& 4000.00 05 5555 EEE RR002 @@@@ 5000.00 06 666 FFF UU003 JJJJ 6000.00 07 777 III II005 PPPP 7000.00 08 8888 TTT TT008 TTTT 8000.00 data1.txt 文件内容如下: AAA 001 1000.00 BBB 001 2000.00 DDD 002 4000.00 EEE 002 5000.00 FFF 003 6000.00 data1的第1列、最后一列和data2的第3列、最后一列是相同的, data1的第2列和data2的第4列的后3位是相同的。 要求:data2中第三列、第四列后3位、第六列完全和data1相同的取出来得到新文件如下内容: 6 01 1111 AAA WW001 $$$$ 1000.00 02 2222 BBB GG001 %%%% 2000.00 04 4444 DDD FF002 &&&& 4000.00 05 5555 EEE RR002 @@@@ 5000.00 06 666 FFF UU003 JJJJ 6000.00 代码: nawk 'NR<=FNR {a[$1]=$1"x"$2"x"$3} NR>FNR { b=substr($4,3); c=$3"x"b"x"$6; if(c==a[$3]) print}' data1.txt data2.txt 执行:直接执行上述代码 解释:本例巧妙地利用了组合字符串(用x来组合),然后用来比较。 当NR<=FNR时,处理第一个文件,当NR>FNR时,处理第二个文件。转载于:https://www.cnblogs.com/demote/archive/2012/05/08/2509090.html
相关资源:数据结构—成绩单生成器