简介

  • awk是一个文本处理工具,通常用于处理数据并生成结果报告
  • awk的命名是它的创始人Alfred Aho、Peter Weinberger和Brian Kernighan姓氏的首个字母组成的

工作模式

  • 读:从文件、管道或标准输入中读入一行然后把它存放到内存中
  • 执行:对每一行数据,根据AWK命令按顺序执行。默认情况是处理每一行数据,也可以指定模式
  • 重复:一直重复上述两个过程直到文件结束

语法格式

  • 第一种形式:awk 'BEGIN{}pattern{commands}END{}' filename

  • 第二种形式:standard output | awk 'BEGIN{}pattern{commands}END{}'

语法格式说明

语法格式 解释
BEGIN{} 正式处理数据之前执行
pattern 匹配模式
{commands} 处理命令,可能多行
END{} 处理完所有匹配数据后执行

内置变量

内置变量对照表

内置变量 含义
$0 整行内容
$1-$n 当前行的第1~n个字段
NF (Number Field) 当前行的字段个数,也就是有多少列
NR (Number Row) 当前行的行号,从1开始计数
FNR (Field Number Row) 多文件处理时,每个文件行号单独计数,都是从0开始
FS (Field Separator) 输入字段分隔符。不指定默认以空格或tab键分割
RS (Row Separator) 输入行分隔符。默认回车换行
OFS (Output Filed Separator) 输出字段分隔符。默认为空格
ORS (Output Row Separator) 输出行分隔符。默认为回车换行
FILENAME 当前输入的文件名字
ARGC 命令行参数个数
ARGV 命令行参数数组

练习

用法 命令
awk输出/etc/passwd每一行(整行)的内容 awk '{print $0}' /etc/passwd
:字段分隔符输出/etc/passwd第一行的内容 awk 'BEGIN{FS=":"}{print $1}' /etc/passwd
:字段分隔符输出/etc/passwd每行字段的个数 awk 'BEGIN{FS=":"}{print NF}' /etc/passwd
输出/etc/passwd每行的行号 awk '{print NR}' /etc/passwd
输出/etc/passwd每行的行号(多个文件,不会单独计数) awk '{print NR}' /etc/passwd /etc/passwd
输出/etc/passwd每行的行号(多个文件,单独计数) awk '{print FNR}' /etc/passwd /etc/passwd
:行分隔符输出/etc/passwd每行(整行)内容 awk 'BEGIN{RS=":"}{print $0}' /etc/passwd
&分隔符输出/etc/passwd第三行的内容 [root@localhost ~]# awk 'BEGIN{FS=":";ORS="&"}{print $3}' /etc/passwd
&分隔符输出,@行分隔符/etc/passwd第一,三行的内容 awk 'BEGIN{FS=":";ORS="&";OFS="@"}{print $1,$3}' /etc/passwd
输出文件内多行的文件名 awk '{print FILENAME}' /etc/passwd
输出命令行参数个数 awk '{print ARGC}' /etc/passwd

格式化输出之printf

printf的格式说明符

格式符 含义
%s 打印字符串
%d 打印十进制数
%f 打印一个浮点数
%x 打印十六进制数
%o 打印八进制数
%e 打印数字的科学计数法形式
%c 打印单个字符的ASCII码

printf的修饰符

修饰符 含义
- 左对齐
+ 右对齐
# 显示8进制在前面加0,显示16进制在前面加0x

练习

格式符示例

用法 命令
以字符串格式打印/etc/passwd中的第7个字段,以”:”作为分隔符 awk 'BEGIN{FS=":"} {printf "%s",$7}' /etc/passwd
以10进制格式打印/etc/passwd中的第3个字段,以”:”作为分隔符 awk 'BEGIN{FS=":"} {printf "%d\n",$3}' /etc/passwd
以浮点数格式打印/etc/passwd中的第3个字段,以”:”作为分隔符 awk 'BEGIN{FS=":"} {printf "%0.3f\n",$3}' /etc/passwd
以16进制数格式打印/etc/passwd中的第3个字段,以”:”作为分隔符 awk 'BEGIN{FS=":"} {printf "%#x\n",$3}' /etc/passwd
以8进制数格式打印/etc/passwd中的第3个字段,以”:”作为分隔符 awk 'BEGIN{FS=":"} {printf "%#o\n",$3}' /etc/passwd
以科学计数法格式打印/etc/passwd中的第3个字段,以”:”作为分隔符 awk 'BEGIN{FS=":"} {printf "%e\n",$3}' /etc/passwd

修饰符示例

用法 命令
左对齐格式 awk 'BEGIN{FS=":"}{printf "%-20s %-20s\n",$1,$7}' /etc/passwd
右对齐格式(默认都是右对齐) awk 'BEGIN{FS=":"}{printf "%-20s %+20s\n",$1,$7}' /etc/passwd
打印8进制或16进制数字是在前面加# awk 'BEGIN{FS=":"} {printf "%#x\n",$3}' /etc/passwd

模式匹配的两种用法

  • 第一种模式匹配:RegExp

  • 第二种模式匹配:关系运算匹配

用法格式对照表

语法格式 含义
RegExp 按正则表达式匹配
关系运算匹配 按关系运算匹配

练习

RegExp示例

用法 命令
匹配/etc/passwd文件行中含有root字符串的所有行 awk 'BEGIN{FS=":"}/root/{print $0}' /etc/passwd
匹配/etc/passwd文件行中以yarn开头的所有行 awk 'BEGIN{FS=":"}/^yarn/{print $0}' /etc/passwd

###关系运算匹配示例

关系运算符

符号 说明
< 小于
> 大于
<= 小于等于
>= 大于等于
== 等于
!= 不等于
~ 匹配正则表达式
!~ 不匹配正则表达式
用法 命令
:为分隔符,匹配/etc/passwd文件中第3个字段小于50的所有行信息 awk 'BEGIN{FS=":"}$3<50{print $0}' /etc/passwd
:为分隔符,匹配/etc/passwd文件中第3个字段大于50的所有行信息 awk 'BEGIN{FS=":"}$3>50{print $0}' /etc/passwd
:为分隔符,匹配/etc/passwd文件中第7个字段为/bin/bash的所有行信息 awk 'BEGIN{FS=":"}$7=="/bin/bash"{print $0}' /etc/passwd
:为分隔符,匹配/etc/passwd文件中第7个字段不为/bin/bash的所有行信息 awk 'BEGIN{FS=":"}$7!="/bin/bash"{print $0}' /etc/passwd
:为分隔符,匹配/etc/passwd中第3个字段包含3个以上数字的所有行信息 awk 'BEGIN{FS=":"}$3~/[0,9]{3,}/{print $0}' /etc/passwd

布尔运算符

符号 说明
||
&&
!
用法 说明
:为分隔符,匹配/etc/passwd文件中包含hdfs或yarn的所有行信息 `awk ‘BEGIN{FS=”:”}$1==”hdfs”
:为分隔符,匹配/etc/passwd文件中第3个字段小于50并且第4个字段大于50的所有行信息 awk 'BEGIN{FS=":"}$3<50 && $4>50 {print $0}' /etc/passwd

表达式用法

awk动作表达式中的算术运算符

运算符 含义
+
-
*
/
%
^** 乘方
++X 在返回X变量之前,X变量加1
X++ 在返回X变量之后,X变量加1

练习

  1. 使用awk计算/etc/services中的空白行(^$)数量

    1
    awk '/^$/{sum++}END{print sum}' /etc/services
  2. 计算学生课程分数平均值,学生课程文件(student.txt)内容如下:

    1
    2
    3
    4
    5
    6
    Allen	80	90	96	98
    Mike 93 98 92 91
    Zhang 78 76 87 92
    Jerry 86 89 68 92
    Han 85 95 75 90
    Li 78 88 98 100
    1
    2
    3
    4
    5
    6
    7
    8
    [root@localhost ~]# awk 'BEGIN{printf "%-8s%-8s%-8s%-8s%-8s%s\n","Name","Chinese","Math","English","Pysical","Average"}{total=$2+$3+$4+$5;AVG=total/4;printf "%-8s%-8d%-8d%-8d%-8d%0.2f\n",$1,$2,$3,$4,$5,AVG}' student.txt
    Name Chinese Math English Pysical Average
    Allen 80 90 96 98 91.00
    Mike 93 98 92 91 93.50
    Zhang 78 76 87 92 83.25
    Jerry 86 89 68 92 83.75
    Han 85 95 75 90 86.25
    Li 78 88 98 100 91.00

条件及循环语句

条件语句

1
2
3
4
5
6
if(条件表达式)
动作1
else if(条件表达式)
动作2
else
动作3

循环语句

while循环

1
2
while(条件表达式)
动作

do while循环

1
2
3
do
动作
while(条件表达式)

for循环

1
2
for(初始化计数器;计数器测试;计数器变更)
动作

练习

  1. 以:为分隔符,只打印/etc/passwd中第3个字段的数值在50-100范围内的行信息

    1
    awk 'BEGIN{FS=":"}{if($3>50 && $3<100) print $0}' /etc/passwd

    使用条件语句进行输出

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    touch script-if.awk
    vim script-if.awk
    BEGIN{
    FS=":"
    }
    {
    if($3<50)
    {
    printf "%-20s%-25s%-5d\n","UUID<50",$1,$3
    }
    else if($3>50 && $3<100)
    {
    printf "%-20s%-25s%-5d\n","50<UUID<100",$1,$3
    }
    else
    {
    printf "%-20s%-25s%-5d\n","UUID>100",$1,$3
    }
    }
    awk -f script-if.awk /etc/passwd
  1. 计算student.txt文件中每个同学的平均分数,并且只打印平均分数大于90的同学姓名和分数信息

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    BEGIN{
    printf "%-10s%-10s%-10s%-10s%-10s%-10s\n","Name","Chinese","English","Math","Physical","Average"
    }
    {
    total=$2+$3+$4+$5
    avg=total/4
    if(avg>90)
    {
    printf "%-10s%-10d%-10d%-10d%-10d%-0.2f\n",$1,$2,$3,$4,$5,avg
    score_chinese+=$2
    score_english+=$3
    score_math+=$4
    score_physical+=$5
    }
    }
    END{

    printf "%-10s%-10d%-10d%-10d%-10d\n","",score_chinese,score_english,score_math,score_physical

    }
    [root@localhost ~]# awk -f script-avg.awk student.txt
  1. 计算1+2+3+4+…+100的和,请使用while、do while、for三种循环方式实现

    • while

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      BEGIN{
      while(i<=100)
      {
      sum+=i
      i++
      }
      print sum
      }
      [root@localhost ~]# awk -f script-while.awk
      5050
    • do while

      1
      2
      3
      4
      5
      6
      7
      8
      9
      BEGIN{
      do{
      sum+=i
      i++
      }while(i<=100)
      print sum
      }
      [root@localhost ~]# awk -f script-do.awk
      5050
  • for

    1
    2
    3
    4
    5
    6
    7
    8
    BEGIN{
    for(i=0;i<=100;i++){
    sum+=i
    }
    print sum
    }
    [root@localhost ~]# awk -f script-for.awk
    5050

字符串函数

字符串函数对照表

函数名 解释 函数返回值
length(str) 计算字符串长度 整数长度值
index(str1,str2) 在str1中查找str2的位置 返回值为位置索引,从1计数
tolower(str) 转换为小写 转换后的小写字符串
toupper(str) 转换为大写 转换后的大写字符串
substr(str,m,n) 从str的m个字符串开始,截取n位 截取后的子串
split(str,arr,fs) 按fs切割字符串,结果保存arr 切割后的子串的个数
match(str,RE) 在str中安装RE查找,返回位置 返回索引位置
sub(RE,RepStr,str) 在str中搜索符合RE的子串,将其替换为RepStr;只替换第一个 替换的个数
Gsub(RE,RepStr,str) 在str中搜索符合RE的子串,将其替换为RepStr;替换所有 替换的个数

练习

  1. :为分隔符,返回/etc/passwd中每行中每个字段的长度

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    BEGIN{
    FS=":"
    }
    {
    i=1
    while(i<=NF)
    {
    if(i==NF)
    printf "%d",length($i)
    else
    printf "%d:",length($i)
    i++
    }
    print ""
    }
    [root@localhost ~]# awk -f script-length.awk /etc/passwd
    • NF:每行有多少列
  2. 搜索字符串”I have a dream”中出现”ea”子串的位置

    1
    2
    awk 'BEGIN{str="I hava a dream";location=index(str,"ea");print location}'
    awk 'BEGIN{str="I hava a dream";location=match(str,"ea");print location}'
  1. 将字符串”Hadoop is a bigdata Framawork”全部转换为小写

    1
    awk 'BEGIN{str="Hadoop is a bigdata Framework";print tolower(str)}'
  1. 将字符串”Hadoop is a bigdata Framawork”全部转换为大写

    1
    awk 'BEGIN{str="Hadoop is a bigdata Framework";print toupper(str)}'
  1. 将字符串”Hadoop Kafka Spark Storm HDFS YARN Zookeeper”,按照空格为分隔符,分隔每部分保存到数组array中

    1
    awk 'BEGIN{str="Hadoop Kafka Spark Storm HDFS YARN Zookeeper";split(str,arr);for(a in arr) print arr[a]}'
  1. 搜索字符串”Tranction 2345 Start:Select * from master”第一个数字出现的位置

    1
    awk 'BEGIN{str="Tranction 2345 Start:Select * from master";location=match(str,/[0-9]/);print location}'
  1. 截取字符串”transaction start”的子串,截取条件从第4个字符开始,截取5位

    1
    awk 'BEGIN{str="transaction start";print substr(str,4,5)}'

    从第4个字符开始,截取剩余的字符串

    1
    awk 'BEGIN{str="transaction start";print substr(str,4)}'
  1. 替换字符串”Tranction 243 Start,Event ID:9002”中第一个匹配到的数字串为$符号

    1
    awk 'BEGIN{str="Tranction 243 Start,Event ID:9002";count=sub(/[0-9]+/,"$",str);print count,str}'

    全部替换

    1
    awk 'BEGIN{str="Tranction 243 Start,Event ID:9002";count=gsub(/[0-9]+/,"$",str);print count,str}'

常用选项

常用选项总结

选项 解释
-v 参数传递
-f 指定脚本文件
-F 指定分隔符
-V 查看awk的版本号

练习

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
[root@localhost ~]# num1=20
[root@localhost ~]# var="hello world"
[root@localhost ~]# awk -v num2="$num1" -v var1="$var" 'BEGIN{print num2,var1}'
20 hello world
[root@localhost ~]# vim script-str.awk
[root@localhost ~]# cat script-str.awk
BEGIN{
str="I have a dream"
location=index(str,"ea")
print location
}
[root@localhost ~]# awk -f script-str.awk
12
[root@localhost ~]# awk -F ":" '{print $7}' /etc/passwd
/bin/bash
……
[root@localhost ~]# awk -F: '{print $7}' /etc/passwd
/bin/bash
……
[root@localhost ~]# awk -V
GNU Awk 4.0.2
Copyright (C) 1989, 1991-2012 Free Software Foundation.
……

数组的用法

学习时,与Shell中的数组进行对比

Shell中数组的用法

array=("Allen" "Mike" "Messi" "Jerry" "Man" "Women")

  • 打印元素:echo ${array[2]} 注意:下标是从0开始 打印所有元素:echo ${array[@]}

  • 打印元素个数:echo ${#array[@]}或者echo ${#array[*]}

  • 打印元素长度:echo ${#array[0]}

  • 给元素赋值: array[1]="Jack"

  • 删除元素:unset array[2] 删除数组所有元素:unset array

  • 分片访问:echo ${array[@]:1:3}访问下标1到3的元素

  • 元素内容替换:echo ${array[@]/e/E}只替换元素的第一个e;echo ${array[@]//e/E} 替换元素中所有的e

  • 数组的遍历: for a in ${array[@]};do echo $a;done

awk中数组的用法

在awk中,使用数组时,不仅可以使用1.2..n作为数组下标,也可以使用字符串作为数组下标,注意:awk数组遍历时,下标时以1开始

当使用1.2.3..n时,直接使用array[2]访问元素;需要遍历数组时,使用以下形式:

1
2
3
4
str="Allen Mike Messi Jerry Man Women"
split(str,array) # 默认空格为分割符,可不写默认分隔符
for(i=1;i<length(array);i++)
print array[i]

当使用字符串作为数组下标时,需要使用array[str]形式访问元素;遍历数组时,使用以下形式:

1
2
3
4
5
array["var1"]="Jin"
array["var2"]="Hao"
array["var3"]="Fang"
for(a in array)
print array[a]
1
2
3
4
5
6
7
8
9
10
11
12
[root@localhost ~]# awk 'BEGIN{str="Allen Mike Jerry Hanmeimei Lilei";split(str,array);for(i=1;i<=length(array);i++) print array[i]}'
Allen
Mike
Jerry
Hanmeimei
Lilei
[root@localhost ~]# awk 'BEGIN{str="Allen Mike Jerry Hanmeimei Lilei";split(str,array);for(a in array) print array[a]}'
Hanmeimei
Lilei
Allen
Mike
Jerry

典型常用例子

  1. 统计主机上所有TCP连接状态数,安装每个TCP状态分类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    [root@localhost ~]# netstat -an | grep tcp | awk '{print $6}'
    LISTEN
    LISTEN
    LISTEN
    ESTABLISHED
    ESTABLISHED
    LISTEN
    LISTEN
    [root@localhost ~]# netstat -an | grep tcp | awk '{array[$6]++}END{for(a in array) print a,array[a]}'
    LISTEN 5
    ESTABLISHED 2
    [root@localhost ~]# netstat -nat |tail -n +3|awk '{print $6}'|sort|uniq -c|sort -rn
    5 LISTEN
    2 ESTABLISHED
  2. 计算横向数据总和,计算纵向数据总和(student.txt)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    [root@localhost ~]# cat student.txt
    Allen 80 90 96 98
    Mike 93 98 92 91
    Zhang 78 76 87 92
    Jerry 86 89 68 92
    Han 85 95 75 90
    Li 78 88 98 100
    [root@localhost ~]# cat script-stu.awk
    BEGIN {
    printf "%-10s%-10s%-10s%-10s%-10s\n", "Name","Chinese","Math","English","Physical","Total"
    }
    {
    total=$2+$3+$4+$5
    chinese_sum+=$2
    math_sum+=$3
    eng_sum+=$4
    phy_sum+=$5
    printf "%-10s%-10d%-10d%-10d%-10d%-10d\n",$1,$2,$3,$4,$5,total
    }
    END {
    printf "%-10s%-10d%-10d%-10d%-10d\n","",chinese_sum,math_sum,eng_sum,phy_sum
    }
    [root@localhost ~]# awk -f script-stu.awk student.txt
    Name Chinese Math English Physical
    Allen 80 90 96 98 364
    Mike 93 98 92 91 374
    Zhang 78 76 87 92 333
    Jerry 86 89 68 92 335
    Han 85 95 75 90 345
    Li 78 88 98 100 364
    500 536 516 563

awk处理生产数据实例

需求描述:利用awk处理日志,并生成结果报告。

生成数据测试脚本如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#!/bin/bash
#

function create_random()
{
min=$1
max=$(($2-$min+1))
num=$(date +%s%N)
echo $(($num%$max+$min))
}

INDEX=1

while true
do
for user in allen mike jerry tracy han lilei
do
COUNT=$RANDOM
NUM1=`create_random 1 $COUNT`
NUM2=`expr $COUNT - $NUM1`
echo "`date '+%Y-%m-%d %H:%M:%S'` $INDEX Batches: user $user insert $COUNT records into database:product table:detail, insert $NUM1 records successfully,failed $NUM2 records" >> ./db.log.`date +%Y%m%d`
INDEX=`expr $INDEX + 1`
done
done

生成的log如下格式:

1
2
3
4
2021-03-07 02:31:30 2407 Batches: user allen insert 2473 records into database:product table:detail, insert 1954 records successfully,failed 519 records
2021-03-07 02:31:30 2408 Batches: user mike insert 27173 records into database:product table:detail, insert 26642 records successfully,failed 531 records
2021-03-07 02:31:30 2409 Batches: user jerry insert 23659 records into database:product table:detail, insert 8085 records successfully,failed 15574 records
……
  1. 统计每个人员分别插入了多少条record进数据库

    1
    2
    3
    4
    输出结果:
    User Total_Records
    allen 493082
    mike 349287
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    [root@localhost ~]# cat exam_1.awk
    BEGIN {
    printf "%-10s%-10s\n","User","Total_Records"
    }
    {
    USER[$6]+=$8
    }
    END {
    for(u in USER)
    printf "%-10s%-20d\n", u,USER[u]
    }
    [root@localhost ~]# awk -f exam_1.awk db.log.20210307
    User Total_Records
    tracy 9369577
    allen 9408437
    mike 9262759
    jerry 9796791
    lilei 9229997
    han 9005836
  1. 统计每个人分别插入成功了多少record,失败了多少record

    1
    2
    3
    4
    输出结果:
    User Sucess_Record Failed_Records
    jerry 3472738 283737
    mike 2738237 28373
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    [root@localhost ~]# cat exam_2.awk
    BEGIN {
    printf "%-10s%-20s%-20s\n","User","Sucess_Record","Failed_Records"
    }
    {
    SUCCESS[$6]+=$14
    FAIL[$6]+=$17
    }
    END {
    for(u in SUCCESS)
    printf "%-10s%-20d%-20d\n",u,SUCCESS[u],FAIL[u]
    }
    [root@localhost ~]# awk -f exam_2.awk db.log.20210307
    User Sucess_Record Failed_Records
    tracy 4542256 4827321
    allen 4870765 4537672
    mike 4575874 4686885
    jerry 5097645 4699146
    lilei 4646997 4583000
    han 4547662 4458174
  1. 将例子1和例子2结合起来,一起输出,输出每个人分别插入多少数据,多少成功,多少失败,并且要格式化输出,加上标题

    1
    2
    3
    4
    5
    输出结果:
    User Total Sucess Failed
    tracy 7472277 3945659 3526618
    allen 7390330 3597157 3793173
    mike 7226579 3679395 3547184
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    root@localhost ~]# cat exam_3.awk
    BEGIN {
    printf "%-10s%-20s%-20s%-20s\n","Total","User","Sucess","Failed"
    }
    {
    TOTAL[$6]+=$8
    SUCCESS[$6]+=$14
    FAIL[$6]+=$17
    }
    END {
    for(u in SUCCESS)
    printf "%-10s%-20d%--20d%-20d\n",u,TOTAL[u],SUCCESS[u],FAIL[u]
    }
    [root@localhost ~]# awk -f exam_3.awk db.log.20210307
    Total User Sucess Failed
    tracy 9369577 4542256 4827321
    allen 9408437 4870765 4537672
    mike 9262759 4575874 4686885
    jerry 9796791 5097645 4699146
    lilei 9229997 4646997 4583000
    han 9005836 4547662 4458174
  1. 在例子3的基础上,加上结尾,统计全部插入记录数,成功记录数,失败记录数

    1
    2
    3
    4
    5
    6
    输出结果:
    User Total Sucess Failed
    tracy 7472277 3945659 3526618
    allen 7390330 3597157 3793173
    mike 7226579 3679395 3547184
    21384945 11222211 10866975
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    [root@localhost ~]# cat exam_4.awk
    BEGIN {
    printf "%-10s%-20s%-20s%-20s\n","Total","User","Sucess","Failed"
    }
    {
    TOTAL[$6]+=$8
    SUCCESS[$6]+=$14
    FAIL[$6]+=$17
    }
    END {
    for(u in SUCCESS) {
    total+=TOTAL[u]
    success+=SUCCESS[u]
    fail+=FAIL[u]
    printf "%-10s%-20d%--20d%-20d\n",u,TOTAL[u],SUCCESS[u],FAIL[u]
    }
    printf "%-10s%-20d%--20d%-20d\n","",total,success,fail
    }
    [root@localhost ~]# awk -f exam_4.awk db.log.20210307
    Total User Sucess Failed
    tracy 9369577 4542256 4827321
    allen 9408437 4870765 4537672
    mike 9262759 4575874 4686885
    jerry 9796791 5097645 4699146
    lilei 9229997 4646997 4583000
    han 9005836 4547662 4458174
    56073397 28281199 27792198
  1. 查找丢失数据的现象,也就是成功+失败的记录数,不等于一共插入的记录数。找出这些数据并显示行号和对应行的日志信息

    1
    [root@localhost ~]# awk '{if($8!=$14+$17) print NR,$0}' db.log.20210307