【转】awk 数组用法【精华贴】
awk的数组,一种关联数组(Associative Arrays),下标可以是数字和字符串。因无需对数组名和元素提前声明,也无需指定元素个数 ,所以awk的数组使用非常灵活。
首先介绍下几个awk数组相关的知识点:
<1>建立数组
- array[index] = value :数组名array,下标index以及相应的值value。
复制代码
<2>读取数组值
- { for (item in array) print array[item]} # 输出的顺序是随机的
- {for(i=1;i<=len;i++) print array[i]} # Len 是数组的长度
复制代码
<3>多维数组,array[index1,index2,……]:SUBSEP是数组下标分割符,默认为“\034”。可以事先设置SUBSEP,也可以直接在SUBSEP的位置输入你要用的分隔符,如:
- awk 'BEGIN{SUBSEP=":";array["a","b"]=1;for(i in array) print i}'
- a:b
- awk 'BEGIN{array["a"":""b"]=1;for(i in array) print i}'
- a:b
复制代码
但,有些特殊情况需要避免,如:
- awk 'BEGIN{
- SUBSEP=":"
- array["a","b:c"]=1 # 下标为“a:b:c”
- array["a:b","c"]=2 #下标同样是“a:b:c”
- for (i in array) print i,array[i]}'
- a:b:c 2 #所以数组元素只有一个。
复制代码
<4>删除数组或数组元素: 使用delete 函数
- delete array #删除整个数组
- delete array[item] # 删除某个数组元素(item)
复制代码
<5>
排序:awk中的asort函数可以实现对数组的值进行排序,不过排序之后的数组下标改为从1到数组的长度。在gawk
3.1.2以后的版本还提供了一个asorti函数,这个函数不是根据关联数组的值,而是根据关联数组的下标排序,即asorti(array)以后,仍
会用数字(1到数组长度)来作为下标,但是array的数组值变为排序后的原来的下标,除非你指定另一个参数如:asorti(a,b)。(非常感谢
lionfun对asorti的指正和补充)
- echo 'aa
- bb
- aa
- bb
- cc' |\
- awk '{a[$0]++}END{l=asorti(a);for(i=1;i<=l;i++)print a[i]}'
- aa
- bb
- cc
- echo 'aa
- bb
- aa
- bb
- cc' |\
- awk '{a[$0]++}END{l=asorti(a,b);for(i=1;i<=l;i++)print b[i],a[b[i]]}'
- aa 2
- bb 2
- cc 1
复制代码
下面说awk数组的实际应用。
1. 除去重复项, 这个不多说, 只给出代码:
- awk '!a[$0]++' file(s)
- awk '!($0 in a){a[$0];print}' file(s)
复制代码
另一种:http://bbs.chinaunix.net/thread-1859344-1-1.html
2. 计算总数(sum),如:
- awk '{name[$0]+=$1};END{for(i in name) print i, name[i]}'
- 再举个例子:
- echo "aaa 1
- aaa 1
- ccc 1
- aaa 1
- bbb 1
- ccc 1" |awk '{a[$1]+=$2}END{for(i in a) print i,a[i]}'
- aaa 3
- bbb 1
- ccc 2
复制代码
3. 查看文件差异。
- cat file1
- aaa
- bbb
- ccc
- ddd
- cat file2
- aaa
- eee
- ddd
- fff
复制代码
<1> 合并file1和file2,除去重复项:
- awk 'NR==FNR{a[$0]=1;print} #读取file1,建立数组a,下标为$0,并赋值为1,然后打印
- NR>FNR{ #读取file2
- if(!(a[$0])) {print } #如果file2 的$0不存在于数组a中,即不存在于file1,则打印。
- }' file1 file2
- aaa
- bbb
- ccc
- ddd
- eee
- fff
复制代码
<2> 提取文件1中有,但文件2中没有:
- awk 'NR==FNR{a[$0]=1} #读取file2,建立数组a,下标为$0,并赋值为1
- NR>FNR{ #读取file1
- if(!(a[$0])) {print } #如果file1 的$0不存在于数组a中,即不存在于file2,则打印。
- }' file2 file1
- bbb
- ccc
复制代码
另:http://bbs.chinaunix.net/viewthr
... &page=1#pid15547885
4. 排序:
- echo "a
- 1
- 0
- b
- 2
- 10
- 8
- 100" |
- awk '{a[$0]=$0} #建立数组a,下标为$0,赋值也为$0
- END{
- len=asort(a) #利用asort函数对数组a的值排序,同时获得数组长度len
- for(i=1;i<=len;i++) print i "\t"a[i] #打印
- }'
- 1 0
- 2 1
- 3 2
- 4 8
- 5 10
- 6 100
- 7 a
- 8 b
复制代码
5. 有序输出:采用(index in array)的方式打印数组值的顺序是随机的,如果要按原序输出,则可以使用下面的方法:http://bbs2.chinaunix.net/viewthread.php?tid=1811279
- awk '{a[$1]=$2
- c[j++]=$1}
- END{
- for(m=0;m<j;m++)print c[m],a[c[m]]
- }'
复制代码
6. 多个文本编辑:这里主要指的是待处理的文本之间的格式上有区别,如分隔符不同,;或是待处理文本需提取的信息的位置不同,如不同的列或行。
<例1>:
- cat file1
- g1.1 2
- g2.2 4
- g2.1 5
- g4.1 3
- cat file2
- g1.1 2
- g1.2 3
- g4.1 4
- cat file3
- g1.2 3
- g5.1 3
复制代码
要求输出:
- g1.1 2 2 -
- g1.2 - 3 3
- g2.2 4 - -
- g2.1 5 - -
- g4.1 3 4 -
- g5.1 - - 3
复制代码
实现代码如下:
- awk '{a[ARGIND" "$1]=$2 # ARGIND是当前命令行文件的位置(从0开始),将它和第一列的value作为下标,建立数组a。
- b[$1] #将第一列的value作为下标,建立数组b,目的是在读完所有文件之后,能得到第一列value的uniqe-list。
- }
- END{
- for(i in b) {
- printf i" "
- for(j=1;j<=ARGIND;j++) printf "%s ", a[j" "i]?a[j" "i]:"-" #此时的ARGIND值为3.
- print ""
- }
- }' file1 file2 file3
复制代码
这里是利用awk的内置变量ARGIND来处理完成对文件的处理。关于ARGIND,ARGV,ARGC的使用,大家可以参考:http://bbs.chinaunix.net/viewthr
... 0335&from=favorites。
当然,我们也可以利用另外一个内置变量FILENAME来完成相同的任务(大家可以先想想怎么写),如下:
- 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>:对上面的数据的格式稍作改动,每个文件的分隔符都一样的情况,但输出要求不变:
- cat file1
- g1.1|2
- g2.2|4
- g2.1|5
- g4.1|3
- cat file2
- g1.1#2
- g1.2#3
- g4.1#4
- cat file3
- g1.2@3
- g5.1@3
复制代码
实现代码如下:
- awk '{a[ARGIND" "$1]=$2
- b[$1]
- }
- END{
- for(i in b) {
- printf i" "
- for(j=2;j<=ARGIND;j+=2) printf "%s ", a[j" "i]?a[j" "i]:"-" # 由于FS的设置也是有对应ARGIND值,所以对ARGIND稍作改动。
- print ""
- }
- }' FS="|" file1 FS="#" file2 FS="@" file3 # 对每个文件分别设置FS的值。
复制代码
因为这个例子的数据比较简单,我们也可以在BEGIN模块中完成对FS值设置,如下:
- 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 同样可以解决问题:
- awk '
- FILENAME=="file1"{FS="|"} # 设置FS
- FILENAME=="file2"{FS="#"} #设置FS
- FILENAME=="file3"{FS="@"} #设置FS
- # 稍显繁琐,不过一目了然
- {$0=$0} #使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
复制代码
推荐一个关于数组处理文件的帖子http://www.chinaunix.net/jh/24/577044.html ,里面有不少例子供大家学习。
7. 文本翻转或移位:二维或多维数组的应用
<例1>:
- Inputfile
- 1 2 3 4 5 6
- 2 3 4 5 6 1
- 3 4 5 6 1 2
- 4 5 6 1 2 3
- Outputfile
- 4 3 2 1
- 5 4 3 2
- 6 5 4 3
- 1 6 5 4
- 2 1 6 5
- 3 2 1 6
- awk '{
- if (max_nf < NF)
- max_nf = NF # 数组第一维的长度
- max_nr = NR # 数组第二维的长度
- for (x = 1; x <= NF; x++)
- vector[x, NR] = $x #建立数组vector
- }
- END {
- for (x = 1; x <= max_nf; x++) {
- for (y = max_nr; y >= 1; --y)
- printf("%s ", vector[x, y])
- printf("\n")
- }
- }'
复制代码
<例2>:来自http://bbs.chinaunix.net/viewthr
... &page=1#pid13339226
有两个文本a和b,要求输出c文本,合并的规则是按照第一行的headline(按字母顺序)合并文本a和b,空缺按“0”补齐。
- cat a.txt
- a b c d
- 1 2 9 7
- 4 5 8 9
- 5 3 6 1
- cat b.txt
- a e f d g
- 9 2 4 7 3
- 4 3 7 9 4
- cat c.txt
- a b c d e f g
- 1 2 9 7 0 0 0
- 4 5 8 9 0 0 0
- 5 3 6 1 0 0 0
- 9 0 0 7 2 4 3
- 4 0 0 9 3 7 4
复制代码
下面我们来参看并解读下Tim大师的代码:
- awk '
- FNR==1{ #FNR==1,即a和b文本的第一行,这个用的真的很巧妙。
- for(i=1;i<=NF;i++){
- b[i]=$i #读取文本的每个元素存入数组b
- c[$i]++} #另建立数组c,并统计每个元素的个数
- next #可以理解为,读取FNR!=1的文本内容。
- }
- {k++ # 统计除去第一行的文本行数
- for(i=1;i<=NF;i++)a[k","b[i]]=$i #利用一个二维数组来保持每个数字的位置, k,b[i]可以理解为每个数字的坐标。
- }
- END{
- l=asorti(c) #利用asorti函数对数组的下标进行排序,并获取数组长度,即输出文件的列数(NF值)
- for(i=1;i<=l;i++)printf c[i]" " # 先打印第一行,相当于headline。
- print ""
- for(i=1;i<=k;i++){
- for(j=1;j<=l;j++)printf a[i","c[j]]?a[i","c[j]]" ":"0 " # 打印二维数组的值。
- print ""}
- }' a.txt b.txt
复制代码
8. 选择性打印:
打印某个关键字前几行,以3行为例:
- seq 20 |awk '/\<10\>/{for(i=NR-3;i<NR;i++)print a[i%3];exit}{a[NR%3]=$0}'
- 7
- 8
- 9
复制代码
利用NR取余数,建立数组,这是一种非常高效的代码。
9. 通过split函数建立数组:数组的下标为从1开始的数字。
- split(s, a [, r]) # s:string, a:array name,[,r]:regular expression。
- echo 'abcd' |awk '{len=split($0,a,"");for(i=1;i<=len;i++) print "a["i"] = " a[i];print "length = " len}'
- a[1] = a
- a[2] = b
- a[3] = c
- a[4] = d
- length = 4
复制代码
10. awk数组使用的小技巧和需要避免的用法:
<1> 嵌套数组:
- awk 'BEGIN{a[1]=3;b[1]=1;print a[b[1]]}'
- 3
复制代码
<2> 下标设为变量或函数:
- awk 'BEGIN{s=123;a[substr(s,2)]=substr(s,1,1);for(i in a)print "index : "i"\nvalue : "a[i]}'
- index : 23
- value : 1
复制代码
<3> 不可以将数组名作为变量使用,否则会报错:
- awk 'BEGIN{a["1"] = 3; delete a;a=3;print a}' #即使你已经使用了delete函数。
- awk: fatal: attempt to use array `a' in a scalar context
复制代码
<4> 数组的长度:
- length(array)
复制代码
<5> match 函数也可以建立数组(你知道么?,版本要求高于gawk
3.1.2)
- echo "foooobazbarrrrr |
- gawk '{ match($0, /(fo+).+(bar*)/, arr) #匹配到的部分自动赋值到arr中,下标从1开始
- print arr[1], arr[2]
- print arr[1, "start"], arr[1, "length"] #二维数组arr[index,"start"]值=RSTART
- print arr[2, "start"], arr[2, "length"] #二维数组arr[index,"length"]值=RLENGTH
- }'
- foooo barrrrr
- 1 5
- 9 7
复制代码
<6>想到过用split清空数组么?
- awk 'BEGIN{
- split("abc",array,"")
- print "array[1] = "array[1],"\narray[2] = "array[2],"\narray[3] = "array[3]
- split("",array)
- print "array[1] = "array[1],"\narray[2] ="array[2],"\narray[3] ="array[3]
- }'
- array[1] = a
- array[2] = b
- array[3] = c
- array[1] =
- array[2] =
- array[3] =
复制代码
【转】awk 数组用法【精华贴】的更多相关文章
- Linux常用基本命令:三剑客命令之-awk数组用法
AWK的数组用法跟javascript类似. 1,定义数组 awk 'BEGIN{a[0]="zhangsan";a[1]="lisi";print a[0]} ...
- Linux sed 和 awk的用法
sed用法: 原文链接:http://www.cnblogs.com/dong008259/archive/2011/12/07/2279897.html sed是一个很好的文件处理工具,本身是一个管 ...
- awk基本用法
1 简介 awk实质是一种编程语言,基本作用在于查找和替换. 2 基本用法 有文本名称为:awk.txt 内容为: john.wang male 30 021-111111 lucy.yang f ...
- <三剑客> 老大:awk命令用法
awk是一种编程语言,用于在linux/unix下对文本和数据进行处理.数据可以来自标准输入(stdin).一 个或多个文件,或其它命令的输出.它支持用户自定义函数和动态正则表达式等先进功能,是lin ...
- awk命令_Linux awk 命令用法详解
本文索引 awk命令格式和选项 awk模式和操作 模式 操作 awk脚本基本结构 awk的工作原理 awk内置变量(预定义变量) 将外部变量值传递给awk awk运算与判断 算术运算符 赋值运算符 逻 ...
- 3.awk数组详解及企业实战案例
awk数组详解及企业实战案例 3.打印数组: [root@nfs-server test]# awk 'BEGIN{array[1]="zhurui";array[2]=" ...
- JavaScript八张思维导图—数组用法
JS基本概念 JS操作符 JS基本语句 JS数组用法 Date用法 JS字符串用法 JS编程风格 JS编程实践 不知不觉做前端已经五年多了,无论是从最初的jQuery还是现在火热的Angular,Vu ...
- 【转】awk数组操作
转自:http://blog.csdn.net/wangran51/article/details/9168361 用awk进行文本处理,少不了就是它的数组处理.那么awk数组有那些特点,一般常见运算 ...
- C# Split 根据组合字符进行拆分数组用法
C# Split 根据组合字符进行拆分数组用法,如下代码: string sql = "aaaaaaaaaa{@}bbbbbbbbbb{@}ccccccc#cccccc"; //1 ...
随机推荐
- git 本地代码到github
一·什么是gitHub? 官网解释:gitHub是一个让无论处于何地的代码工作者能工作于同一个项目,同一个版本的平台.(GitHub is a code hosting platform for ve ...
- nodejs 做后台的一个完整业务整理
大家知道js现在不仅仅可以写前端界面而且可以写后端的业务了,这样js就可以写一个全栈的项目.这里介绍一个nodejs + express + mongodb + bootstap 的全栈项目. 1.安 ...
- ssm工程集成mybatis分页插件pagehelper
1 首先需要在mybatis的配置文件SqlMapConfig.xml文件中配置pagehelper插件 <plugins> <plugin interceptor=" ...
- 高可用高性能分布式文件系统FastDFS进阶keepalived+nginx对多tracker进行高可用热备
在上一篇 分布式文件系统FastDFS如何做到高可用 中已经介绍了FastDFS的原理和怎么搭建一个简单的高可用的分布式文件系统及怎么访问. 高可用是实现了,但由于我们只设置了一个group,如果现在 ...
- deeplearning.ai 人工智能行业大师访谈 Ruslan Salakhutdinov 听课笔记
Ruslan Salakhutdinov一方面是苹果的研究主管,另一方面是CMU的教授. 1. Ruslan说自己进入深度学习完全是运气,他在多伦多大学读硕士,然后休学了一年,他在金融领域工作,那时候 ...
- 【Java学习笔记之十八】Javadoc注释的用法
Javadoc注释的用法 Java 文档 // 注释一行/* ...... */ 注释若干行/** ...... */ 注释若干行,并写入 javadoc 文档 通常这种注释的多行写法如下: /*** ...
- Big Event in HDU(多重背包套用模板)
http://acm.hdu.edu.cn/showproblem.php?pid=1171 Big Event in HDU Time Limit: 10000/5000 MS (Java/Othe ...
- Linux6.X图形界面如何打开终端以及如何将终端加入右键
今天刚安装了一个centos 6.9图形界面的系统,安装完成后,鼠标右击没有打开终端的按钮,在网上查了一些资料,搞明白了,分享给大家. 在左上角菜单[Applications]--->[Syst ...
- Apache Shiro 核心概念
转自:http://blog.csdn.net/peterwanghao/article/details/8015571 Shiro框架中有三个核心概念:Subject ,SecurityManage ...
- struts中用kindeditor实现的图片上传并且显示在页面上
做公司网站的时候由于需要在内容属性中加入图片,所以就有了这个问题,本来一开始找几篇文章看都是讲修改kindeditor/jsp/file_manager_json.jsp和upload_json.js ...