awk数组的学习心得

时间:2021-02-02 16:23:25
.blockcode {overflow:hidden;margin:10px 0;padding:5px 10px;background:#F7F7F7;color:#000;}

from :

http://bbs.chinaunix.net/thread-2312439-1-1.html

http://pencilblog.sinaapp.com/?p=283

本帖最后由 yinyuemi 于 2011-06-26 00:29 编辑

在文本处理的工作中,awk的数组是必不可少的工具,在这里,同样以总结经验和教训的方式和大家分享下我的一些学习心得,如有错误的地方,请大家指正和补充。

awk的数组,一种关联数组(Associative Arrays),下标可以是数字和字符串。因无需对数组名和元素提前声明,也无需指定元素个数 ,所以awk的数组使用非常灵活。
首先介绍下几个awk数组相关的知识点:

<1>建立数组
  1. array[index] = value :数组名array,下标index以及相应的值value。
复制代码
<2>读取数组值
  1. { for (item in array)  print array[item]} # 输出的顺序是随机的
  2. {for(i=1;i<=len;i++)  print array[i]} # Len 是数组的长度
复制代码
<3>多维数组,array[index1,index2,……]:SUBSEP是数组下标分割符,默认为“\034”。可以事先设定SUBSEP,也可以直接在SUBSEP的位置输入你要用的分隔符,如:
  1. awk 'BEGIN{SUBSEP=":";array["a","b"]=1;for(i in array) print i}'
  2. a:b
  3. awk 'BEGIN{array["a"":""b"]=1;for(i in array) print i}'
  4. a:b
复制代码
但,有些特殊情况需要避免,如:
  1. awk 'BEGIN{
  2. SUBSEP=":"
  3. array["a","b:c"]=1               # 下标为“a:b:c”
  4. array["a:b","c"]=2               #下标同样是“a:b:c”
  5. for (i in array) print i,array[i]}'
  6. a:b:c 2                                 #所以数组元素只有一个。
复制代码
<4>删除数组或数组元素: 使用delete 函数
  1. delete array                     #删除整个数组
  2. delete array[item]           # 删除某个数组元素(item)
复制代码
<5> 排序:awk中的asort函数可以实现对数组的值进行排序,不过排序之后的数组下标改为从1到数组的长度。在gawk 3.1.2以后的版本还提供了一个asorti函数,这个函数不是依据关联数组的值,而是依据关联数组的下标排序,即asorti(array)以后,仍会用数字(1到数组长度)来作为下标,但是array的数组值变为排序后的原来的下标,除非你指定另一个参数如:asorti(a,b)。(非常感谢lionfun对asorti的指正和补充awk数组的学习心得

  1. echo 'aa
  2. bb
  3. aa
  4. bb
  5. cc' |\
  6. awk '{a[$0]++}END{l=asorti(a);for(i=1;i<=l;i++)print a[i]}'
  7. aa
  8. bb
  9. cc

  10. echo 'aa
  11. bb
  12. aa
  13. bb
  14. cc' |\
  15. awk '{a[$0]++}END{l=asorti(a,b);for(i=1;i<=l;i++)print b[i],a[b[i]]}'
  16. aa 2
  17. bb 2
  18. cc 1
复制代码


下面说awk数组的实际应用。

1.  除去重复项, 这个不多说, 只给出代码:
  1. awk '!a[$0]++' file(s)                  
  2. awk '!($0 in a){a[$0];print}' file(s)   
复制代码
另一种:http://bbs.chinaunix.net/thread-1859344-1-1.html

2. 计算总数(sum),如:
  1. awk  '{name[$0]+=$1};END{for(i in name) print  i, name[i]}'

  2. 再举个例子:

  3. echo "aaa 1
  4. aaa 1
  5. ccc 1
  6. aaa 1
  7. bbb 1
  8. ccc 1" |awk '{a[$1]+=$2}END{for(i in a) print i,a[i]}'
  9. aaa 3
  10. bbb 1
  11. ccc 2
复制代码
3. 查看文件差异。
  1. cat file1
  2. aaa
  3. bbb
  4. ccc
  5. ddd
  6. cat file2
  7. aaa
  8. eee
  9. ddd
  10. fff
复制代码
<1>  合并file1和file2,除去重复项:
  1. awk 'NR==FNR{a[$0]=1;print}   #读取file1,建立数组a,下标为$0,并赋值为1,然后打印
  2. NR>FNR{                   #读取file2
  3. if(!(a[$0])) {print }      #如果file2 的$0不存在于数组a中,即不存在于file1,则打印。
  4. }' file1 file2
  5. aaa
  6. bbb
  7. ccc
  8. ddd
  9. eee
  10. fff
复制代码
<2> 提取文件1中有,但文件2中没有:
  1. awk 'NR==FNR{a[$0]=1}           #读取file2,建立数组a,下标为$0,并赋值为1
  2. NR>FNR{                   #读取file1
  3. if(!(a[$0])) {print }      #如果file1 的$0不存在于数组a中,即不存在于file2,则打印。
  4. }' file2 file1
  5. bbb
  6. ccc
复制代码
另:http://bbs.chinaunix.net/viewthr ... &page=1#pid15547885

4.  排序:
  1. echo "a
  2. 1
  3. 0
  4. b
  5. 2
  6. 10
  7. 8
  8. 100" |
  9. awk '{a[$0]=$0} #建立数组a,下标为$0,赋值也为$0
  10. END{
  11. len=asort(a)      #利用asort函数对数组a的值排序,同时获得数组长度len
  12. for(i=1;i<=len;i++) print i "\t"a[i]  #打印
  13. }'
  14. 1       0
  15. 2       1
  16. 3       2
  17. 4       8
  18. 5       10
  19. 6       100
  20. 7       a
  21. 8       b
复制代码
5.  有序输出:采用(index in array)的方式打印数组值的顺序是随机的,如果要按原序输出,则可以使用下面的方法:http://bbs2.chinaunix.net/viewthread.php?tid=1811279
  1. awk '{a[$1]=$2
  2. c[j++]=$1}
  3. END{
  4. for(m=0;m<j;m++)print c[m],a[c[m]]
  5. }'
复制代码
6.  多个文本编辑:这里主要指的是待处理的文本之间的格式上有区别,如分隔符不同,;或是待处理文本需提取的信息的位置不同,如不同的列或行。
<例1>:
  1. cat file1
  2. g1.1 2
  3. g2.2 4
  4. g2.1 5
  5. g4.1 3
  6. cat file2
  7. g1.1 2
  8. g1.2 3
  9. g4.1 4
  10. cat file3
  11. g1.2 3
  12. g5.1 3
复制代码
要求输出:
  1. g1.1 2 2 -
  2. g1.2 - 3 3
  3. g2.2 4 - -
  4. g2.1 5 - -
  5. g4.1 3 4 -
  6. g5.1 - - 3
复制代码
实现代码如下:
  1. awk '{a[ARGIND" "$1]=$2 # ARGIND是当前命令行文件的位置(从0开始),将它和第一列的value作为下标,建立数组a。
  2.        b[$1]   #将第一列的value作为下标,建立数组b,目的是在读完所有文件之后,能得到第一列value的uniqe-list。
  3.         }
  4. END{
  5.         for(i in b) {
  6.                 printf i" "
  7.                 for(j=1;j<=ARGIND;j++) printf "%s ", a[j" "i]?a[j" "i]:"-" #此时的ARGIND值为3.
  8. print ""
  9.                 }
  10.         }' file1 file2 file3
复制代码
这里是利用awk的内置变量ARGIND来处理完成对文件的处理。关于ARGIND,ARGV,ARGC的使用,大家可以参考:http://bbs.chinaunix.net/viewthr ... 0335&from=favorites
当然,我们也可以利用另外一个内置变量FILENAME来完成相同的任务(大家可以先想想怎么写),如下:
  1. awk '{a[FILENAME" "$1]=$2;b[$1];c[FILENAME]}END{for(i in b) {printf i" ";for(j in c) printf "%s ", a[j" "i]?a[j" "i]:"-";print""}}' file1 file2 file3
复制代码
<例2>:对上面的数据的格式稍作改动,每个文件的分隔符都一样的情况,但输出要求不变:
  1. cat file1
  2. g1.1|2
  3. g2.2|4
  4. g2.1|5
  5. g4.1|3
  6. cat file2
  7. g1.1#2
  8. g1.2#3
  9. g4.1#4
  10. cat file3
  11. g1.2@3
  12. g5.1@3
复制代码
实现代码如下:
  1. awk '{a[ARGIND" "$1]=$2
  2. b[$1]
  3. }
  4. END{
  5. for(i in b) {
  6. printf i" "
  7. for(j=2;j<=ARGIND;j+=2) printf "%s ", a[j" "i]?a[j" "i]:"-" # 由于FS的设置也是有对应ARGIND值,所以对ARGIND稍作改动。
  8. print ""
  9. }
  10. }' FS="|" file1 FS="#" file2 FS="@" file3 # 对每个文件分别设置FS的值。
复制代码
因为这个例子的数据比较简单,我们也可以在BEGIN模块中完成对FS值设置,如下:
  1. awk 'BEGIN{FS="[|#@]"}{a[ARGIND" "$1]=$2; b[$1]}END{for(i in b) {printf i" ";for(j=1;j<=ARGIND;j++) printf "%s ", a[j" "i]?a[j" "i]:"-"; print ""}}' file1 file2 file3
复制代码
利用FILENAME 同样可以解决问题:
  1. awk '
  2. FILENAME=="file1"{FS="|"}    # 设置FS
  3. FILENAME=="file2"{FS="#"}   #设置FS
  4. FILENAME=="file3"{FS="@"}  #设置FS
  5. # 稍显繁琐,不过一目了然
  6. {$0=$0}                                   #使FS生效。
  7. {a[ARGIND" "$1]=$2; b[$1]}
  8. END{ for(i in b) {printf i" "; for(j=1;j<=ARGIND;j++) printf "%s ", a[j" "i]?a[j" "i]:"-"; print ""}
  9. }' file1 file2 file3
复制代码
推荐一个关于数组处理文件的帖子http://www.chinaunix.net/jh/24/577044.html ,里面有不少例子供大家学习。

7.  文本翻转或移位:二维或多维数组的应用
<例1>:
  1. Inputfile
  2. 1 2 3 4 5 6
  3. 2 3 4 5 6 1
  4. 3 4 5 6 1 2
  5. 4 5 6 1 2 3
  6. Outputfile
  7. 4 3 2 1
  8. 5 4 3 2
  9. 6 5 4 3
  10. 1 6 5 4
  11. 2 1 6 5
  12. 3 2 1 6

  13. awk '{
  14.      if (max_nf < NF)
  15.           max_nf = NF # 数组第一维的长度
  16.      max_nr = NR      # 数组第二维的长度
  17.      for (x = 1; x <= NF; x++)
  18.           vector[x, NR] = $x #建立数组vector
  19. }
  20. END {
  21.      for (x = 1; x <= max_nf; x++) {
  22.           for (y = max_nr; y >= 1; --y)
  23.                printf("%s ", vector[x, y])
  24.           printf("\n")
  25.      }
  26. }'
复制代码
<例2>:来自http://bbs.chinaunix.net/viewthr ... &page=1#pid13339226
有两个文本a和b,要求输出c文本,合并的规则是按照第一行的headline(按字母顺序)合并文本a和b,空缺按“0”补齐。
  1. cat a.txt
  2. a b c d
  3. 1 2 9 7
  4. 4 5 8 9
  5. 5 3 6 1
  6. cat b.txt
  7. a e f d g
  8. 9 2 4 7 3
  9. 4 3 7 9 4
  10. cat c.txt
  11. a b c d e f g
  12. 1 2 9 7 0 0 0
  13. 4 5 8 9 0 0 0
  14. 5 3 6 1 0 0 0
  15. 9 0 0 7 2 4 3
  16. 4 0 0 9 3 7 4
复制代码
下面我们来参看并解读下Tim大师的代码:
  1. awk '
  2. FNR==1{    #FNR==1,即a和b文本的第一行,这个用的真的很巧妙。
  3.         for(i=1;i<=NF;i++){
  4.                 b[i]=$i    #读取文本的每个元素存入数组b
  5.                 c[$i]++}  #另建立数组c,并统计每个元素的个数
  6.                 next          #可以理解为,读取FNR!=1的文本内容。
  7.         }
  8. {k++                                     # 统计除去第一行的文本行数
  9. for(i=1;i<=NF;i++)a[k","b[i]]=$i  #利用一个二维数组来保持每个数字的位置, k,b[i]可以理解为每个数字的坐标。
  10. }
  11. END{
  12.         l=asorti(c)          #利用asorti函数对数组的下标进行排序,并获取数组长度,即输出文件的列数(NF值)
  13.         for(i=1;i<=l;i++)printf c[i]" " # 先打印第一行,相当于headline。
  14.         print ""
  15.         for(i=1;i<=k;i++){
  16.                 for(j=1;j<=l;j++)printf a[i","c[j]]?a[i","c[j]]" ":"0 " # 打印二维数组的值。
  17.                 print ""}
  18.         }' a.txt b.txt
复制代码
8.  选择性打印:
打印某个关键字前几行,以3行为例:
  1. seq 20 |awk '/\<10\>/{for(i=NR-3;i<NR;i++)print a[i%3];exit}{a[NR%3]=$0}'
  2. 7
  3. 8
  4. 9
复制代码
利用NR取余数,建立数组,这是一种非常高效的代码。

9. 通过split函数建立数组:数组的下标为从1开始的数字。
  1. split(s, a [, r]) # s:string, a:array name,[,r]:regular expression。
  2. echo 'abcd' |awk '{len=split($0,a,"");for(i=1;i<=len;i++) print "a["i"] = " a[i];print "length = " len}'
  3. a[1] = a
  4. a[2] = b
  5. a[3] = c
  6. a[4] = d
  7. length = 4
复制代码
10. awk数组使用的小技巧和需要避免的用法:

<1> 嵌套数组:
  1. awk 'BEGIN{a[1]=3;b[1]=1;print a[b[1]]}'
  2. 3
复制代码
<2> 下标设为变量或函数:
  1. awk 'BEGIN{s=123;a[substr(s,2)]=substr(s,1,1);for(i in a)print "index : "i"\nvalue : "a[i]}'
  2. index : 23
  3. value : 1
复制代码
<3> 不可以将数组名作为变量使用,否则会报错:
  1. awk 'BEGIN{a["1"] = 3; delete a;a=3;print a}'  #即使你已经使用了delete函数。
  2. awk: fatal: attempt to use array `a' in a scalar context
复制代码
<4> 数组的长度:
  1. length(array)  
复制代码
<5> match 函数也可以建立数组(你知道么?awk数组的学习心得,版本要求高于gawk 3.1.2)
  1. echo "foooobazbarrrrr |
  2. gawk '{ match($0, /(fo+).+(bar*)/, arr)  #匹配到的部分自动赋值到arr中,下标从1开始
  3.           print arr[1], arr[2]
  4.           print arr[1, "start"], arr[1, "length"]  #二维数组arr[index,"start"]值=RSTART
  5.           print arr[2, "start"], arr[2, "length"]  #二维数组arr[index,"length"]值=RLENGTH
  6.           }'
  7. foooo barrrrr
  8. 1 5
  9. 9 7
复制代码
<6>想到过用split清空数组么?awk数组的学习心得
  1. awk 'BEGIN{
  2. split("abc",array,"")
  3. print "array[1] = "array[1],"\narray[2] = "array[2],"\narray[3] = "array[3]
  4. split("",array)
  5. print "array[1] = "array[1],"\narray[2] ="array[2],"\narray[3] ="array[3]
  6. }'
  7. array[1] = a
  8. array[2] = b
  9. array[3] = c
  10. array[1] =
  11. array[2] =
  12. array[3] =
复制代码

[转载]awk用法小结

深入讨论awk
1.awk不仅是一个工具,它是一种语言。其涉及的条件操作符有:
<,<=,>,>=,==,!=,!~(不匹配正则表达式), ~ (匹配正则表达式)
2. 逻辑操作符有:&& (and), || (or), ! (not)
3.awk的内置变量
ARGC 命令行参数个数
ARGV 命令行参数排列
ENVIRON 支持队列中系统环境变量的使用
FILENAME awk浏览的文件名
FNR 浏览的文件名
FS 设置输入域分隔符,等价于命令行-F选项
NF 浏览记录的域个数
NR 已读的记录数
OFS 输出域分隔符
ORS 输出记录分隔符
RS 控制记录分隔符
awk -F ‘#’ ‘{print NF,NR,$0,ARGV[1],ENVIRON["USER"]}’ test.txt 以域为分隔符,打印域的个数,已读的记录数,整行信息,第一个参数(0的话是awk)及用户(最后一个是取得系统的环境变量)
4.awk的字符串函数
gsub(r,s) 在整个$0中用s替代r
gsub(r,s,t) 在整个t中用s替代r
index(s,t) 返回s中字符串t的第一个位置
length(s) 返回s的长度
match(s,r) 测试s是否包含匹配的r的字符串
split(s,a,fs) 用fs(分割符)将s分成序列a
sprint(fmt,exp) 返回fmt格式化后的exp
sub(r,s) 用$0中最左边最长的字串代替s
substr(s,p) 返回字符串s中从p开始的部分
substr(s,p,n) 返回字符串s中从p开始长度为n的部分
example: awk -F ‘#’ ‘{if (gsub(“s”,”S”,$1)) print $1}’ test.txt 以#为分割符,用”S”代替test.txt中每行第一个域中的”s”,并打印第一个域
awk -F ‘#’ ‘{print (index($1,”s”))}’ text.txt 打印“s”在每一行第一个域中的位置,若为0表示没有这个字符
5.awk中的转义字符
“b 退格键
“t tab键
“f 走纸换页
“ddd 八进制值
“n 新行
“c 任意其他特殊字符,如”"为反斜杠符号
“r 回车键
example: awk -F ‘#’ ‘{print (index($2,’s')), “”t”,$2}’ test.txt 打印”s”在第二个域中的位置、退格(相当于键入tab键)、第二个域的内容
6.printf修饰符
%c ASCII字符
%d 整数
%f 浮点数
%e 浮点数,科学记数法
%g awk决定使用哪种浮点数转换,e或者f
%o 八进制数
%s 字符串
%x 十六进制数
example: awk -F ‘#’ ‘{printf “%c”n”,$1}’ test.txt 打印test.txt文件中的第一个域的ASCII码 (注意”%c”n”与”$1″之间的”,” 是不可以忽略的)
7.awk数组
awk中数组叫做关联数组(associative arrays),因为下标记可以是数也
可以是串。awk中的数组不必提前声明,也不必声明大小。数组元素用0或
空串来初始化,这根据上下文而定。
awk ‘BEGIN {print split(“as#qw#1234″,array2,”#”)}’ 表示以”#”为分割符,将”as#qw#1234″分割到array2数组中,并打印数组的长度
awk ‘BEGIN {split(“as#qw#1234″,array2,”#”); print array[1]}’ 如上,并打印该数组的第一个元素。(注意:这里的是数组是从下标1开始的)
8.举例分析:
(1) awk ‘{if ($1~/^21[0-9]/) print $0}’ test.txt |wc -l 匹配test.txt中第一个域为210-219开头的行,并通过管道计算其数量。
(2)awk ‘{if ($4~/^”[07"/Jul"/2004/) print $0 }' test.txt | awk '{if ($7=="/htm/free_call.php") print $0} ' |wc -l 匹配test.txt中第四个域以 "[07/Jul/2004" 开头的且第7个域为"/htm/free_call.php"的所有行,并计算其数量。该语句本来的意思是:统计2004年7月24日访问 /htm/free_call.php的次数。
(3)以下是awk_array.sh的文件内容
#!/bin/awk -f #注明是awk的语法,若无此行则按bash的语法编译会出错
#awk_array.sh
BEGIN{ #BEGIN模式中的命令
FS="#"
score["0-60"]=0 #score数组索引为”0-60″的元素(awk语法允许用字符串索引)
score["60-70"]=0
score["70-80"]=0
score["80-90"]=0
score["90-100"]=0
student["junior"]=0
student["senior"]=0
}
{
{ if ($1<60) #如果第一个域的值小于60
score["0-60"]++ #score数组中索引为”0-60″的元素值+1
}
{ if($1>=60 && $1<70)
score["60-70"]++
}
{ if($1>=70 && $1<80)
score["70-80"]++
}
{ if($1>=80 && $1<90)
score["80-90"]++
}
{ if($1>=90&&$1<=100)
score["90-100"]++
}
}
{ #另senior_junior依次为student数组中的索引(有几个就循环几次)
for (senior_junior in student)
{if ($2==senior_junior)
student[senior_junior]++
}
}
END{
{ for (number in score) print “the score”,number,”has”,score[number],”students”}
{ for (senior_junior in student) print “The class has “,student[senior_junior],senior_junior,”students” }
}
若有文件grade.txt如下:
85#senior
87#junior
78#junior
69#senior
56#junior
98#senior
83#senior
输入命令./awk.sh grade.txt 则输出如下:
the score 0-60 has 1 students
the score 70-80 has 1 students
the score 90-100 has 1 students
the score 60-70 has 1 students
the score 80-90 has 3 students
The class has 4 senior students
The class has 3 junior students
——————————————————————————————————————————-
awk 用法:awk ‘ pattern {action} ‘
变量名 含义
ARGC 命令行变元个数
ARGV 命令行变元数组
FILENAME 当前输入文件名
FNR 当前文件中的记录号
FS 输入域分隔符,默认为一个空格
RS 输入记录分隔符
NF 当前记录里域个数
NR 到目前为止记录数
OFS 输出域分隔符
ORS 输出记录分隔符
1、awk ‘/101/’             file 显示文件file中包含101的匹配行。
awk ‘/101/,/105/’       file
awk ‘$1 == 5′          file
awk ‘$1 == “CT”‘       file 注意必须带双引号
awk ‘$1 * $2 >100 ‘    file
awk ‘$2 >5 && $2<=15′     file
2、awk ‘{print NR,NF,$1,$NF,}’ file 显示文件file的当前记录号、域数和每一行的第一个和最后一个域。
awk ‘/101/ {print $1,$2 + 10}’ file 显示文件file的匹配行的第一、二个域加10。
awk ‘/101/ {print $1$2}’   file
awk ‘/101/ {print $1 $2}’ file 显示文件file的匹配行的第一、二个域,但显示时域中间没有分隔符。
3、df | awk ‘$4>1000000 ‘       通过管道符获得输入,如:显示第4个域满足条件的行。
4、awk -F “|” ‘{print $1}’ file 按照新的分隔符“|”进行操作。
awk   ‘BEGIN { FS=”[: "t|]” }
{print $1,$2,$3}’       file 通过设置输入分隔符(FS=”[: "t|]“)修改输入分隔符。
Sep=”|”
awk -F $Sep ‘{print $1}’   file 按照环境变量Sep的值做为分隔符。
awk -F ‘[ :"t|]‘ ‘{print $1}’ file 按照正则表达式的值做为分隔符,这里代表空格、:、TAB、|同时做为分隔符。
awk -F ‘[][]‘ ‘{print $1}’ file 按照正则表达式的值做为分隔符,这里代表[、]
5、awk -f awkfile       file 通过文件awkfile的内容依次进行控制。
cat awkfile
/101/{print “”047 Hello! “047″} –遇到匹配行以后打印 ‘ Hello! ‘.”047代表单引号。
{print $1,$2}                –因为没有模式控制,打印每一行的前两个域。
6、awk ‘$1 ~ /101/ {print $1}’ file 显示文件中第一个域匹配101的行(记录)。
7、awk ‘BEGIN { OFS=”%”}
{print $1,$2}’           file 通过设置输出分隔符(OFS=”%”)修改输出格式。
8、awk ‘BEGIN { max=100 ;print “max=” max}          BEGIN 表示在处理任意行之前进行的操作。
{max=($1 >max ?$1:max); print $1,”Now max is “max}’ file 取得文件第一个域的最大值。
(表达式1?表达式2:表达式3 相当于:
if (表达式1)
表达式2
else
表达式3
awk ‘{print ($1>4 ? “high “$1: “low “$1)}’ file
9、awk ‘$1 * $2 >100 {print $1}’ file 显示文件中第一个域匹配101的行(记录)。
10、awk ‘{$1 == ‘Chi’ {$3 = ‘China’; print}’ file 找到匹配行后先将第3个域替换后再显示该行(记录)。
awk ‘{$7 %= 3; print $7}’   file 将第7域被3除,并将余数赋给第7域再打印。
11、awk ‘/tom/ {wage=$2+$3; printf wage}’ file 找到匹配行后为变量wage赋值并打印该变量。
12、awk ‘/tom/ {count++;}
END {print “tom was found “count” times”}’ file END表示在所有输入行处理完后进行处理。
13、awk ‘gsub(/”$/,”");gsub(/,/,”"); cost+=$4;
END {print “The total is $” cost>”filename”}’ file gsub函数用空串替换$和,再将结果输出到filename中。
1 2 3 $1,200.00
1 2 3 $2,300.00
1 2 3 $4,000.00
awk ‘{gsub(/”$/,”");gsub(/,/,”");
if ($4>1000&&$4<2000) c1+=$4;
else if ($4>2000&&$4<3000) c2+=$4;
else if ($4>3000&&$4<4000) c3+=$4;
else c4+=$4; }
END {printf   “c1=[%d];c2=[%d];c3=[%d];c4=[%d]“n”,c1,c2,c3,c4}”‘ file
通过if和else if完成条件语句
awk ‘{gsub(/”$/,”");gsub(/,/,”");
if ($4>3000&&$4<4000) exit;
else c4+=$4; }
END {printf   “c1=[%d];c2=[%d];c3=[%d];c4=[%d]“n”,c1,c2,c3,c4}”‘ file
通过exit在某条件时退出,但是仍执行END操作。
awk ‘{gsub(/”$/,”");gsub(/,/,”");
if ($4>3000) next;
else c4+=$4; }
END {printf   “c4=[%d]“n”,c4}”‘ file
通过next在某条件时跳过该行,对下一行执行操作。
14、awk ‘{ print FILENAME,$0 }’ file1 file2 file3>fileall 把file1、file2、file3的文件内容全部写到fileall中,格式为
打印文件并前置文件名。
15、awk ‘ $1!=previous { close(previous); previous=$1 }
{print substr($0,index($0,” “) +1)>$1}’ fileall 把合并后的文件重新分拆为3个文件。并与原文件一致。
16、awk ‘BEGIN {“date”|getline d; print d}’       通过管道把date的执行结果送给getline,并赋给变量d,然后打印。
17、awk ‘BEGIN {system(“echo “”Input your name:”"c”"”); getline d;print “”nYour name is”,d,”"b!”n”}’
通过getline命令交互输入name,并显示出来。
awk ‘BEGIN {FS=”:”; while(getline< “/etc/passwd” >0) { if($1~”050[0-9]_”) print $1}}’
打印/etc/passwd文件中用户名包含050x_的用户名。
18、awk ‘{ i=1;while(i
awk ‘{ for(i=1;i
type file|awk -F “/” ‘
{ for(i=1;i
{ if(i==NF-1) { printf “%s”,$i }
else { printf “%s/”,$i } }}’             显示一个文件的全路径。
用for和if显示日期
awk   ‘BEGIN {
for(j=1;j<=12;j++)
{ flag=0;
printf “”n%d月份”n”,j;
for(i=1;i<=31;i++)
{
if (j==2&&i>28) flag=1;
if ((j==4||j==6||j==9||j==11)&&i>30) flag=1;
if (flag==0) {printf “%02d%02d “,j,i}
}
}
}’
19、在awk中调用系统变量必须用单引号,如果是双引号,则表示字符串
Flag=abcd
awk ‘{print ‘$Flag’}’ 结果为abcd
awk ‘{print   “$Flag”}’ 结果为$Flag

深入讨论awk
1.awk不仅是一个工具,它是一种语言。其涉及的条件操作符有:
<,<=,>,>=,==,!=,!~(不匹配正则表达式), ~ (匹配正则表达式)
2. 逻辑操作符有:&& (and), || (or), ! (not)
3.awk的内置变量
ARGC 命令行参数个数
ARGV 命令行参数排列
ENVIRON 支持队列中系统环境变量的使用
FILENAME awk浏览的文件名
FNR 浏览的文件名
FS 设置输入域分隔符,等价于命令行-F选项
NF 浏览记录的域个数
NR 已读的记录数
OFS 输出域分隔符
ORS 输出记录分隔符
RS 控制记录分隔符
awk -F ‘#’ ‘{print NF,NR,$0,ARGV[1],ENVIRON["USER"]}’ test.txt 以域为分隔符,打印域的个数,已读的记录数,整行信息,第一个参数(0的话是awk)及用户(最后一个是取得系统的环境变量)
4.awk的字符串函数
gsub(r,s) 在整个$0中用s替代r
gsub(r,s,t) 在整个t中用s替代r
index(s,t) 返回s中字符串t的第一个位置
length(s) 返回s的长度
match(s,r) 测试s是否包含匹配的r的字符串
split(s,a,fs) 用fs(分割符)将s分成序列a
sprint(fmt,exp) 返回fmt格式化后的exp
sub(r,s) 用$0中最左边最长的字串代替s
substr(s,p) 返回字符串s中从p开始的部分
substr(s,p,n) 返回字符串s中从p开始长度为n的部分
example: awk -F ‘#’ ‘{if (gsub(“s”,”S”,$1)) print $1}’ test.txt 以#为分割符,用”S”代替test.txt中每行第一个域中的”s”,并打印第一个域
awk -F ‘#’ ‘{print (index($1,”s”))}’ text.txt 打印“s”在每一行第一个域中的位置,若为0表示没有这个字符
5.awk中的转义字符
“b 退格键
“t tab键
“f 走纸换页
“ddd 八进制值
“n 新行
“c 任意其他特殊字符,如”"为反斜杠符号
“r 回车键
example: awk -F ‘#’ ‘{print (index($2,’s')), “”t”,$2}’ test.txt 打印”s”在第二个域中的位置、退格(相当于键入tab键)、第二个域的内容
6.printf修饰符
%c ASCII字符
%d 整数
%f 浮点数
%e 浮点数,科学记数法
%g awk决定使用哪种浮点数转换,e或者f
%o 八进制数
%s 字符串
%x 十六进制数
example: awk -F ‘#’ ‘{printf “%c”n”,$1}’ test.txt 打印test.txt文件中的第一个域的ASCII码 (注意”%c”n”与”$1″之间的”,” 是不可以忽略的)
7.awk数组
awk中数组叫做关联数组(associative arrays),因为下标记可以是数也
可以是串。awk中的数组不必提前声明,也不必声明大小。数组元素用0或
空串来初始化,这根据上下文而定。
awk ‘BEGIN {print split(“as#qw#1234″,array2,”#”)}’ 表示以”#”为分割符,将”as#qw#1234″分割到array2数组中,并打印数组的长度
awk ‘BEGIN {split(“as#qw#1234″,array2,”#”); print array[1]}’ 如上,并打印该数组的第一个元素。(注意:这里的是数组是从下标1开始的)
8.举例分析:
(1) awk ‘{if ($1~/^21[0-9]/) print $0}’ test.txt |wc -l 匹配test.txt中第一个域为210-219开头的行,并通过管道计算其数量。
(2)awk ‘{if ($4~/^”[07"/Jul"/2004/) print $0 }' test.txt | awk '{if ($7=="/htm/free_call.php") print $0} ' |wc -l 匹配test.txt中第四个域以 "[07/Jul/2004" 开头的且第7个域为"/htm/free_call.php"的所有行,并计算其数量。该语句本来的意思是:统计2004年7月24日访问 /htm/free_call.php的次数。
(3)以下是awk_array.sh的文件内容
#!/bin/awk -f #注明是awk的语法,若无此行则按bash的语法编译会出错
#awk_array.sh
BEGIN{ #BEGIN模式中的命令
FS="#"
score["0-60"]=0 #score数组索引为”0-60″的元素(awk语法允许用字符串索引)
score["60-70"]=0
score["70-80"]=0
score["80-90"]=0
score["90-100"]=0
student["junior"]=0
student["senior"]=0
}
{
{ if ($1<60) #如果第一个域的值小于60
score["0-60"]++ #score数组中索引为”0-60″的元素值+1
}
{ if($1>=60 && $1<70)
score["60-70"]++
}
{ if($1>=70 && $1<80)
score["70-80"]++
}
{ if($1>=80 && $1<90)
score["80-90"]++
}
{ if($1>=90&&$1<=100)
score["90-100"]++
}
}
{ #另senior_junior依次为student数组中的索引(有几个就循环几次)
for (senior_junior in student)
{if ($2==senior_junior)
student[senior_junior]++
}
}
END{
{ for (number in score) print “the score”,number,”has”,score[number],”students”}
{ for (senior_junior in student) print “The class has “,student[senior_junior],senior_junior,”students” }
}
若有文件grade.txt如下:
85#senior
87#junior
78#junior
69#senior
56#junior
98#senior
83#senior
输入命令./awk.sh grade.txt 则输出如下:
the score 0-60 has 1 students
the score 70-80 has 1 students
the score 90-100 has 1 students
the score 60-70 has 1 students
the score 80-90 has 3 students
The class has 4 senior students
The class has 3 junior students

——————————————————————————————————————————-
awk 用法:awk ‘ pattern {action} ‘
变量名 含义
ARGC 命令行变元个数
ARGV 命令行变元数组
FILENAME 当前输入文件名
FNR 当前文件中的记录号
FS 输入域分隔符,默认为一个空格
RS 输入记录分隔符
NF 当前记录里域个数
NR 到目前为止记录数
OFS 输出域分隔符
ORS 输出记录分隔符
1、awk ‘/101/’             file 显示文件file中包含101的匹配行。
awk ‘/101/,/105/’       file
awk ‘$1 == 5′          file
awk ‘$1 == “CT”‘       file 注意必须带双引号
awk ‘$1 * $2 >100 ‘    file
awk ‘$2 >5 && $2<=15′     file
2、awk ‘{print NR,NF,$1,$NF,}’ file 显示文件file的当前记录号、域数和每一行的第一个和最后一个域。
awk ‘/101/ {print $1,$2 + 10}’ file 显示文件file的匹配行的第一、二个域加10。
awk ‘/101/ {print $1$2}’   file
awk ‘/101/ {print $1 $2}’ file 显示文件file的匹配行的第一、二个域,但显示时域中间没有分隔符。
3、df | awk ‘$4>1000000 ‘       通过管道符获得输入,如:显示第4个域满足条件的行。
4、awk -F “|” ‘{print $1}’ file 按照新的分隔符“|”进行操作。
awk   ‘BEGIN { FS=”[: "t|]” }
{print $1,$2,$3}’       file 通过设置输入分隔符(FS=”[: "t|]“)修改输入分隔符。
Sep=”|”
awk -F $Sep ‘{print $1}’   file 按照环境变量Sep的值做为分隔符。
awk -F ‘[ :"t|]‘ ‘{print $1}’ file 按照正则表达式的值做为分隔符,这里代表空格、:、TAB、|同时做为分隔符。
awk -F ‘[][]‘ ‘{print $1}’ file 按照正则表达式的值做为分隔符,这里代表[、]
5、awk -f awkfile       file 通过文件awkfile的内容依次进行控制。
cat awkfile
/101/{print “”047 Hello! “047″} –遇到匹配行以后打印 ‘ Hello! ‘.”047代表单引号。
{print $1,$2}                –因为没有模式控制,打印每一行的前两个域。
6、awk ‘$1 ~ /101/ {print $1}’ file 显示文件中第一个域匹配101的行(记录)。
7、awk ‘BEGIN { OFS=”%”}
{print $1,$2}’           file 通过设置输出分隔符(OFS=”%”)修改输出格式。
8、awk ‘BEGIN { max=100 ;print “max=” max}          BEGIN 表示在处理任意行之前进行的操作。
{max=($1 >max ?$1:max); print $1,”Now max is “max}’ file 取得文件第一个域的最大值。
(表达式1?表达式2:表达式3 相当于:
if (表达式1)
表达式2
else
表达式3
awk ‘{print ($1>4 ? “high “$1: “low “$1)}’ file
9、awk ‘$1 * $2 >100 {print $1}’ file 显示文件中第一个域匹配101的行(记录)。
10、awk ‘{$1 == ‘Chi’ {$3 = ‘China’; print}’ file 找到匹配行后先将第3个域替换后再显示该行(记录)。
awk ‘{$7 %= 3; print $7}’   file 将第7域被3除,并将余数赋给第7域再打印。
11、awk ‘/tom/ {wage=$2+$3; printf wage}’ file 找到匹配行后为变量wage赋值并打印该变量。
12、awk ‘/tom/ {count++;}
END {print “tom was found “count” times”}’ file END表示在所有输入行处理完后进行处理。
13、awk ‘gsub(/”$/,”");gsub(/,/,”"); cost+=$4;
END {print “The total is $” cost>”filename”}’ file gsub函数用空串替换$和,再将结果输出到filename中。
1 2 3 $1,200.00
1 2 3 $2,300.00
1 2 3 $4,000.00
awk ‘{gsub(/”$/,”");gsub(/,/,”");
if ($4>1000&&$4<2000) c1+=$4;
else if ($4>2000&&$4<3000) c2+=$4;
else if ($4>3000&&$4<4000) c3+=$4;
else c4+=$4; }
END {printf   “c1=[%d];c2=[%d];c3=[%d];c4=[%d]“n”,c1,c2,c3,c4}”‘ file
通过if和else if完成条件语句
awk ‘{gsub(/”$/,”");gsub(/,/,”");
if ($4>3000&&$4<4000) exit;
else c4+=$4; }
END {printf   “c1=[%d];c2=[%d];c3=[%d];c4=[%d]“n”,c1,c2,c3,c4}”‘ file
通过exit在某条件时退出,但是仍执行END操作。
awk ‘{gsub(/”$/,”");gsub(/,/,”");
if ($4>3000) next;
else c4+=$4; }
END {printf   “c4=[%d]“n”,c4}”‘ file
通过next在某条件时跳过该行,对下一行执行操作。
14、awk ‘{ print FILENAME,$0 }’ file1 file2 file3>fileall 把file1、file2、file3的文件内容全部写到fileall中,格式为
打印文件并前置文件名。
15、awk ‘ $1!=previous { close(previous); previous=$1 }
{print substr($0,index($0,” “) +1)>$1}’ fileall 把合并后的文件重新分拆为3个文件。并与原文件一致。
16、awk ‘BEGIN {“date”|getline d; print d}’       通过管道把date的执行结果送给getline,并赋给变量d,然后打印。
17、awk ‘BEGIN {system(“echo “”Input your name:”"c”"”); getline d;print “”nYour name is”,d,”"b!”n”}’
通过getline命令交互输入name,并显示出来。
awk ‘BEGIN {FS=”:”; while(getline< “/etc/passwd” >0) { if($1~”050[0-9]_”) print $1}}’
打印/etc/passwd文件中用户名包含050x_的用户名。
18、awk ‘{ i=1;while(i
awk ‘{ for(i=1;i
type file|awk -F “/” ‘
{ for(i=1;i
{ if(i==NF-1) { printf “%s”,$i }
else { printf “%s/”,$i } }}’             显示一个文件的全路径。
用for和if显示日期
awk   ‘BEGIN {
for(j=1;j<=12;j++)
{ flag=0;
printf “”n%d月份”n”,j;
for(i=1;i<=31;i++)
{
if (j==2&&i>28) flag=1;
if ((j==4||j==6||j==9||j==11)&&i>30) flag=1;
if (flag==0) {printf “%02d%02d “,j,i}
}
}
}’
19、在awk中调用系统变量必须用单引号,如果是双引号,则表示字符串
Flag=abcd
awk ‘{print ‘$Flag’}’ 结果为abcd
awk ‘{print   “$Flag”}’ 结果为$Flag

 

from:http://blog.163.com/wghbeyond@126/blog/static/3516618120105229827829/