AWK

5 分钟读完

基本语法范例

  • awk '{print $0}' file1 ... file2 ...
  • awk -f check.awk file1 ... file2 ...

稍微复杂一点的建议用后面的这个方式。

假定我们有个access.log日志,以 ### 作为字段的分隔符,包含时间/请求IP/响应编码/请求url

1
2
2018-12-11 11:11:11 #### 44.44.44.44 ### 200 ### /mod1/url1
2018-12-11 12:12:12 #### 55.55.55.55 ### 200 ### /mod2/url2

可以用这个awk脚本count-by-ip.awk来根据IP来源做请求量统计

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# awk -f count-by-ip.awk access.log
BEGIN {
  FS = ' ### '
}

{
  arr[$2]++;
}

END {
  for (tag in arr){
    print tag, arr[tag]
  }
}
  • 复杂一点的业务逻辑,建议在开头写注释。如果调用方式也特殊,建议注释里加上调用范例。
  • awk中$0表示这一行,$1...$n表示各个field
  • BEGIN中做初始化准备工作,一般适合在这里做环境变量设置;
  • END中做收尾工作,一般在这里输出统计结果;

进一步的小技巧

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# awk -f count-by-ip.awk access.log
BEGIN {
  FS = ' ### '
}

{
  # records before "2018-12-11 13:00:00"
  if ($1 > "2018-12-11 13:00:00") exit;

  # skip wrong line.
  if (!$2) next;

  arr[$2]++;
}

END {
  for (tag in arr){
    print tag, arr[tag]
  }
}
  • next语句结束当前这行数据的处理,继续下一行,相当于continue;这个是一个特别好的编程习惯;
  • exit语句将结束awk的行处理流程,相当于break,如果有END模块将执行;

案例

使用 - 集成管道操作的输入

1
2
3
4
5
6
7
8
9
10
$ echo 123 | tee 1.log
123

$ echo '456' | awk '{print $0}' 1.log -
123
456

$ echo '456' | awk '{print $0}' - 1.log
456
123

利用NR和FNR做【引入新列】

  1. 需求
    将其中一个文件中的列“引入到另外一个文件中”,例如:
    • id->name 关系表,id2name.lst
      1
      2
      
      zhangsan 张三
      lisi 李四
      
    • 数据条目,有id字段,record.lst
      1
      2
      3
      
      zhangsan 100
      lisi  99
      wangwu 90
      

      需求是将name加入到数据中。

  2. 解决方案convert.awk ```

    awk -f convert.awk id2name.lst record.lst

    { if (NR == FNR) { map[$1] = $2; next; }

print $1, map[$1] ? map[$1] : “蒙面人” , $2 }

1
2
3
4
5
6
7
3. 结果验证
```shell
$ awk -f convert.awk id2name.lst record.lst
zhangsan 张三 100
lisi 李四 99
wangwu 蒙面人 90
  1. 扩展

留下评论