三千年读史无外乎功名利禄,九万里悟道终归是诗酒田园。

awk进阶用法- 数组/复合索引数组/遍历顺序指定

一、awk数组去除重复行

root@debian:~/awk# cat x.log
abc
def
ghi
abc
ghi
xyz

mnopq
abc
root@debian:~/awk# awk '{arr[$0]++}END{for(i in arr)print i}' x.log    ###由于用了for循环,遍历是无序的

def
mnopq
abc
ghi
xyz

如果想不打乱顺序按原样输出,则不能使用for

root@debian:~/awk# awk '!arr[$0]++{print $0}' x.log
abc
def
ghi
xyz

mnopq
root@debian:~/awk

分析:!arr[$0]++作为partten,只有第一次出现的值为空(为假),取反后则为真,执行main代码块

二、指定遍历顺序

awk数组为关联数组,默认情况下,for(idx in arr)遍历数组时顺序是不可预测的。
但gawk提供了PROCINFO["sorted_in"]来指定遍历的元素顺序。它可以设置为两种类型的值:

  • 设置为用户自定义函数
  • 设置为下面这些awk预定义好的值:
预定义值 说明
@unsorted 默认值,遍历时无序
@ind_str_asc 索引按字符串比较方式升序遍历
@ind_str_desc 索引按字符串比较方式降序遍历
@ind_num_asc 索引强制按照数值比较方式升序遍历,无法转换的字符串索引将当做数值0进行比较
@ind_num_desc 索引强制按照数值比较方式降序遍历,无法转换的字符串索引将当做数值0进行比较
@val_type_asc 按值升序比较,数值类型>字符串类型>数组类型,即num>str>arr
@val_type_desc 按值降序比较,数值类型<字符串类型<数组类型,即num<str<arr
@val_str_asc 按值升序比较,数值转化成字符串再比较,而数组出现在尾部
@val_str_desc 按值降序比较,数值转化成字符串再比较,而数组出现在头部
@val_num_asc 按值升序比较,字符串转换为数值再比较,而数组出现在尾部
@val_num_desc 按值降序比较,字符串转化成数值再比较,而数组出现在头部
  • 示例一,按值降序排序
    root@debian:~/awk# awk '{arr[$0]=$0;PROCINFO["sorted_in"]="@val_num_desc"}END{for(idx in arr)print arr[idx]}'< <(seq 6)
    6
    5
    4
    3
    2
    1
    root@debian:~/awk# 
  • 示例二,按索引降序排序
    root@debian:~/awk# awk '{arr[$0]=$0;PROCINFO["sorted_in"]="@ind_num_desc"}END{for(idx in arr)print idx"-->"arr[idx]}'< <(seq 6)
    6-->6
    5-->5
    4-->4
    3-->3
    2-->2
    1-->1
    root@debian:~/awk

三、awk统计行和单词出现次数

  • 示例一,统计次数并按照值排序:

    root@debian:~/awk# awk '{arr[$0]++;PROCINFO["sorted_in"]="@val_num_asc"}END{for(idx in arr)print idx"-->"arr[idx]}' x.log
    -->1
    def-->1
    mnopq-->1
    xyz-->1
    ghi-->2
    abc-->3
    root@debian:~/awk#
  • 示例二,统计单词出现次数:

    
    root@debian:~/awk# cat x.log
    abc
    def abc
    ghi
    abc word
    ghi   hello
    xyz  world

mnopq
abc
root@debian:~/awk# awk '{for(i=1;i<=NF;i++){arr[$i]++}}END{for(idx in arr)print idx":"arr[idx]}' x.log
hello:1
def:1
mnopq:1
abc:4
world:1
ghi:2
xyz:1
word:1
root@debian:~/awk#

- 示例三,统计tcp[6]出现的state次数
```bash
root@debian:~/awk# netstat -tanp|awk '/tcp6?/{arr[$6]++}END{for(idx in arr)print idx":"arr[idx]}'
LISTEN:20
CLOSE_WAIT:126
ESTABLISHED:4
root@debian:~/awk#

四、根据字段取出最大值

root@debian:~/awk# cat aaa.txt
file 100
dir 11
file 100
dir 11
file 102
dir 112
file 120
dir 119
root@debian:~/awk# awk '{if(arr[$1]<$2){arr[$1]=$2}}END{for(idx in arr) print idx":"arr[idx]}' aaa.txt
dir:119
file:120
root@debian:~/awk#

使用三目运算法简化:

root@debian:~/awk# awk '{arr[$1]=($2>arr[$1]) ? $2: arr[$1]}END{for(i in arr)print i":"arr[i]}' aaa.txt
dir:119
file:120

五、awk复合索引数组

  • 示例,逆时针倒转数据:
root@debian:~/awk# cat c.txt
1 2 3 4 5 6
2 3 4 5 6 1
3 4 5 6 1 2
4 5 6 1 2 3
root@debian:~/awk# awk '{nf=NF;nr=NR;for(i=1;i<=NF;i++){arr[NR,i]=$i}}END{for(i=1;i<=nf;i++){for(j=nr;j>=1;j--)if(j==1)printf "%s\n",arr[j,i];else printf "%s ",arr[j,i]}}' c.txt
4 3 2 1
5 4 3 2
6 5 4 3
1 6 5 4
2 1 6 5
3 2 1 6
root@debian:~/awk# awk '{nf=NF;nr=NR;for(i=1;i<=NF;i++){arr[NR,i]=$i}}END{for(i=1;i<=nf;i++){for(j=nr;j>=1;j--)if(j%nr==1)printf "%s\n",arr[j,i];else printf "%s ",arr[j,i]}}' c.txt
4 3 2 1
5 4 3 2
6 5 4 3
1 6 5 4
2 1 6 5
3 2 1 6
root@debian:~/awk#

将数组元素按照[NR,NF]的格式存储,END读取完整个文件并初始化数组之后,使用for循环格式化输出即可。

六、测试数据类型是否为数组

  • isarray(arr)可用于检测arr是否为数组,是则返回1,否则返回0。
  • 对比typeof(arr)可返回arr的数据类型,如果arr为数组,则返回"array"
    示例:
    root@debian:~/awk# awk 'BEGIN{arr[a]="a";print typeof(arr)=="array";print isarray(arr);arr["null"];print length(arr)}'
    1
    1
    2
    root@debian:~/awk#
赞(39)
转载请注明出处:RokasYang's Blog » awk进阶用法-