linux三剑客之awk
awk工作模式
awk是一个文本处理工具,通常用于处理数据并生成结果报告,按行处理
语法格式
第一种形式:awk 'BEGIN{}pattern{commands}END{}' filename
第二种形式:standard out | awk 'BEGIN{}pattern{commands}END{}'
第三种形式:awk -f scripts.awk filename
将处理的命令写到文件中,然后指定这个文件执行awk
语法格式 |
解释 |
BEGIN{} |
正式处理数据之前执行(读取第一行处理之前) |
pattern |
匹配模式(不写默认对所有行进行处理) |
{commands} |
处理匹配到内容的命令 |
END{} |
处理完所有匹配数据后执行(最后一行处理完毕之后) |
awk内置变量
内置变量 |
含义 |
$0 |
整行内容 |
$1-$n |
当前行的第1-n个字段 |
NF(Number Field) |
当前行的字段个数,也就是有多少列 |
NR(Number Row) |
当前行的行号,从1开始计数 |
FNR(File Number Row) |
多文件处理时,每个文件行号单独计数,都是从1开始(NR多个文件的情况下,是累加计数,第二个文件不会从1开始计数,而是接着第一个文件的数值开始累加计数) |
FS(Field Separator) |
输入字段分隔符(输入给awk命令处理)。不指定默认以空格或tab键分割 |
RS(Row Separator) |
输入行分隔符。默认回车换行 |
OFS(Output Field Separator) |
输出字段分隔符(awk命令处理完毕输出)。默认空格 |
ORS(Output Row Separator) |
输出行分隔符。默认回车换行 |
FILENAME |
当前处理的文件名称 |
ARGC |
命令行参数个数 |
ARGV |
命令行参数数组 |
# 输出/etc/passwd文件的全部内容 [root@VM_0_13_centos ~]# awk '{print $0}' /etc/passwd # 输出/etc/passwd中的用户名,每一行以:为分隔符的第一个字段 [root@VM_0_13_centos ~]# awk 'BEGIN{FS=":"}{print $1}' /etc/passwd # 输出/etc/passwd中每一行字段的个数,每一行以:为分隔符 [root@VM_0_13_centos ~]# awk 'BEGIN{FS=":"}{print NF}' /etc/passwd 7 # 输出/etc/passwd中每一行的行号(从1开始) [root@VM_0_13_centos ~]# awk '{print NR}' /etc/passwd 1 2 3 4 #输出test.txt文件和/etc/passwd中每一行的行号(使用NR两个文件的行号没有单独计数,而是累加)(使用FNR两个文件的行号是单独计数,都从1开始) [root@VM_0_13_centos ~]# awk '{print NR}' /etc/passwd test.txt 1 2 3 4 5 6 7 8 9 [root@VM_0_13_centos ~]# awk '{print FNR}' test.txt /etc/passwd 1 2 3 4 5 1 2 3 # 输入分隔符(FS、RS) [root@VM_0_13_centos ~]# cat list.txt Hadoop|Spark|Flume--JAVA|Python|Scala|Go--Allen|Mike|XYZ [root@VM_0_13_centos ~]# awk 'BEGIN{RS="--"}{print $0}' list.txt Hadoop|Spark|Flume JAVA|Python|Scala|Go Allen|Mike|XYZ
[root@VM_0_13_centos ~]# awk 'BEGIN{RS="--";FS="|"}{print $3}' list.txt Flume Scala XYZ
# 输出分隔符(OFS、ORS) [root@VM_0_13_centos ~]#cat list.txt Hadoop|Spark|Flume--JAVA|Python|Scala|Go--Allen|Mike|XYZ [root@VM_0_13_centos ~]# awk 'BEGIN{RS="--";FS="|";ORS="&"}{print $3}' list.txt Flume&Scala&XYZ [root@VM_0_13_centos ~]# awk 'BEGIN{RS="--";FS="|";ORS="&"}{print $1 $3}' list.txt HadoopFlume&JAVAScala&AllenXYZ [root@VM_0_13_centos ~]# awk 'BEGIN{RS="--";FS="|";ORS="&"}{print $1,$3}' list.txt Hadoop Flume&JAVA Scala&Allen XYZ [root@VM_0_13_centos ~]# awk 'BEGIN{RS="--";FS="|";ORS="&";OFS="@"{print $1,$3}' list.txt Hadoop@Flume&JAVA@Scala&Allen@XYZ #命令行参数个数 # awk本身作为一个参数,list.txt作为一个参数,所以是两个参数 # awk不指定匹配条件,默认对文本的每一行进行处理,处理每一行都执行{commands},即处理每一行都打印参数个数,所以输出了3个,因为文件有三行 [root@VM_0_13_centos ~]# awk '{print ARGC}' list.txt 2 2 2 |
awk格式化输出之printf
printf的格式说明符 |
|
格式符 |
含义 |
%s |
打印字符串 |
%d |
打印十进制数 |
%f |
打印一个浮点数 |
%x |
打印十六进制数 |
%o |
打印八进制数 |
%e |
打印数字的科学技术法形式 |
%c |
打印单个字符的ASCII码 |
printf的修饰符 |
|
修饰符 |
含义 |
- |
左对齐 |
+ |
右对齐 |
# |
显示8进制在前面加0,显示16进制在前面加0x |
[root@VM_0_13_centos ~]# awk 'BEGIN{FS=":"}{printf "%s\n",$1}' /etc/passwd
root
bin
daemon
adm
[root@VM_0_13_centos ~]# awk 'BEGIN{FS=":"}{printf "%s\t%s\n",$1,$7}' /etc/passwd
root /bin/bash
bin /sbin/nologin
daemon /sbin/nologin
adm /sbin/nologin
# %20s,指定该字符串固定占用20个字符的长度,如果字符数不够20个,用空格补齐
[root@VM_0_13_centos ~]# awk 'BEGIN{FS=":"}{printf "%20s%20s\n",$1,$7}' /etc/passwd
root /bin/bash
bin /sbin/nologin
daemon /sbin/nologin
adm /sbin/nologin
[root@VM_0_13_centos ~]# awk 'BEGIN{FS=":"}{printf "%-20s%-20s\n",$1,$7}' /etc/passwd
root /bin/bash
bin /sbin/nologin
daemon /sbin/nologin
adm /sbin/nologin
格式符示例:
1.以字符串格式打印/etc/passwd中的第7个字段,以”:”作为分隔符
awk ‘BEGIN{FS=”:”} {printf “%s\n”, $7}’ /etc/passwd
2.以10进制格式打印/etc/passwd中的第3个字段,以”:”作为分隔符
awk ‘BEGIN{FS=”:”} {printf “%d\n”, $7}’ /etc/passwd
3.以浮点数打印/etc/passwd中的第3个字段,以”:”作为分隔符(%0.2f,保留小数点后两位)
awk ‘BEGIN{FS=”:”} {printf “%0.2f\n”, $7}’ /etc/passwd
4. 以16进制格式打印/etc/passwd中的第3个字段,以”:”作为分隔符
awk ‘BEGIN{FS=”:”} {printf “%#x\n”, $7}’ /etc/passwd
5. 以8进制格式打印/etc/passwd中的第3个字段,以”:”作为分隔符
awk ‘BEGIN{FS=”:”} {printf “%#o\n”, $7}’ /etc/passwd
6. 以科学计算法格式打印/etc/passwd中的第3个字段,以”:”作为分隔符
awk ‘BEGIN{FS=”:”} {printf “%e\n”, $7}’ /etc/passwd
修饰符示例
1.左对齐格式
awk 'BEGIN{FS=":"}{printf "%-20s%-20s\n",$1,$7}' /etc/passwd
awk模式匹配的两种用法
语法格式 |
含义 |
RegExp |
按正则表达式匹配 |
关系运算 |
按关系运算匹配(等于、大于、小于等) |
RegExp
匹配/etc/passwd文件行中含有root字符串的所有行(正则匹配/root/)
awk ‘BEGIN{FS=”:”}/root/{print $0}’ /etc/passwd
匹配/etc/passwd文件行中以yarn开头的所有行
awk ‘BEGIN{FS=”:”}/^yarn/{print $0}’ /etc/passwd
运算符匹配
关系运算符匹配:
< 小于
> 大于
<= 小于等于
>= 大于等于
== 等于(既可以用于数字,也可以用于字符串)
!= 不等于(既可以用于数字,也可以用于字符串)
~/reg/ 匹配正则表达式
!~/reg/ 不匹配正则表达式
1.以:为分隔符,匹配/etc/passwd文件中第3个字段小于50的所有行信息
awk 'BEGIN{FS=":"}$3<50{print $0}' /etc/passwd
2.以:为分隔符,匹配/etc/passwd文件中第3个字段大于50的所有行信息
awk 'BEGIN{FS=":"}$3>50{print $0}' /etc/passwd
3.以:为分隔符,匹配/etc/passwd文件中第7个字段为/bin/bash的所有行信息
awk 'BEGIN{FS=":"}$7=="/bin/bash"{print $0}' /etc/passwd
4.以:为分隔符,匹配/etc/passwd文件中第7个字段不为/bin/bash的所有行信息
awk 'BEGIN{FS=":"}$7!="/bin/bash"{print $0}' /etc/passwd
5. 匹配/etc/passwd文件中第3个字段包含3个以上数字的所有行信息
awk 'BEGIN{FS=":"}$3~/[0-9]{3,}/{print $0}' /etc/passwd
布尔运算符匹配
|| 或
&& 与
! 非
1.以:为分隔符,匹配/etc/passwd文件中包含hdfs或yarn的所有行信息
awk 'BEGIN{FS=":"}$1=="hdfs"||$1=="yarn" {print $0}' /etc/passwd
2.以:为分隔符,匹配/etc/passwd文件中第3个字段小于50并且第4个字段大于50的所有行信息
awk 'BEGIN{FS=":"}$3<50 && $4>50 {print $0}' /etc/passwd
3.以:为分隔符,匹配/etc/passwd文件中第3个字段小于50并且第7个字段包含/bin/bash的所有行信息
awk 'BEGIN{FS=":"}$3<50 && $7~/\/bin\/bash/ {print $0}' /etc/passwd
awk中的表达式用法
awk动作表达式中的算数运算符 |
|
运算符 |
含义 |
+ |
加 |
- |
减 |
* |
乘 |
/ |
除 |
% |
模 |
^或** |
乘方 |
++x |
在返回x变量之前,x变量加1 |
x++ |
在返回x变量之后,x变量加1 |
awk动作中的条件及循环语句
条件语句:
if(条件表达式)
{
动作1
}
else if(条件表达式)
{
动作2
}
else
{
动作3
}
循环语句:
while循环:
while(条件表达式)
{
动作
}
do while循环:
do
{
动作
}
while(条件表达式)
for循环:
for(初始化计数器;计数器测试;计数器变更)
{
动作
}
for(i in arr)
{
动作
}
1.以:为分隔符,只打印/etc/passwd中第3个字段的数字在50-100范围内的行信息
awk -f scripts.awk /etc/passwd
vim scripts.awk
BEGIN{
FS=":"
}
{
if($3<50)
{
printf "%-20s%-25s%-5d\n","UID<50",$1,$3
}
else if($3>50 && $3<100)
{
printf "%-20s%-25s%-5d\n","50<UID<100",$1,$3
}
else
{
printf "%-20s%-25s%-5d\n","UID>100",$1,$3
}
}
2.计算下列每个同学的平均分数,并且只打印平均分数大于90 的同学姓名和分数信息
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
vim student.awk
BEGIN{
printf "%-10s%-10s%-10s%-10s%-10s%-10s\n","Name","Chiness","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
}
awk -f student.awk student.txt
awk中的字符串函数
函数名 |
解释 |
函数返回值 |
length(str) |
计算字符串长度 |
整数长度值 |
index(str1,str2) |
在str1中查找str2的位置 |
返回值为位置索引,从1计数 |
tolower(str) |
转换为小写 |
转换后的小写字符串 |
toupper(str) |
转换为大写 |
转换后的大写字符串 |
substr(str,m,n) |
从str的m个字符开始,截取n位,n不指定默认截取到字符串结尾 |
截取后的子串 |
split(str,arr,fs) |
按fs切割字符串,结果保存到数组arr中,该数组的下标是从1开始,和shell数组从0开始不一样,fs默认为空格 |
切割后的子串个数 |
match(str,/RE/) |
在str中按照RE查找,返回位置 |
返回索引位置 |
sub(RE,RepStr,str) |
在str中搜索符合RE的子串,将其替换为RepStr,只替换第一个匹配到的 |
替换的个数 |
gsub(RE,RepStr,str) |
在str中搜索符合RE的子串,将其替换为RepStr,替换所有 |
替换的个数 |
1.以:为分隔符,返回/etc/passwd中每行中每个字段的长度
BEGIN{
FS=":"
}
{
i=1
while(i<=NF)
{
if(i==NF)
{
printf "%d",length($i)
}
else
{
printf "%d:",length($i)
}
i++
}
printf "\n"
}
2.搜索字符串"I have a dream"中出现"ea"子串的位置
awk 'BEGIN{str="I have a dream";location=index(str,"ea");print location}'
awk 'BEGIN{str="I have a dream";location=match(str,"ea");print location}'
3.将字符串"Hadoop is a bigdata Framework"全部转换成小写
awk 'BEGIN{str="Hadoop is a bigdata Framework";print tolower(str)}'
4.将字符串"Hadoop is a bigdata Framework"全部转换成大写
awk 'BEGIN{str="Hadoop is a bigdata Framework";print toupper(str)}'
5.将字符串"Hadoop Kafka Spark Storm HDFS YARN Zookeeper",按照空格为分隔符,分隔每部分保存到数组arr中
awk 'BEGIN{str="Hadoop Kafka Spark Storm HDFS YARN Zookeeper";split(str,arr," ");for(a in arr){print arr[a]}}'
6.搜索字符串"Tranction 2345 Start:Select * from master"第一个数字出现的位置
awk 'BEGIN{str="Tranction 2345 Start:Select * from master";location=match(str,/[0-9]/);print location}'
7.截取字符串"transaction start"的子串,截取条件从第4个字符开始,截取5位
awk 'BEGIN{str="transaction start";print substr(str,4,5)}'
8.替换字符串"Tranction 243 Start,Event ID:9002"中第一个匹配到的数字串替换为$符号
awk 'BEGIN{str="Tranction 243 Start,Event ID:9002";count=sub(/[0-9]+/,"$",str);print count,str}'
1 Tranction $ Start,Event ID:9002
awk中的常用选项
选项 |
解释 |
-v |
参数传递(在向awk中传递变量(awk外定义的变量)的时候,变量都要加双引号)(awk -v num="$num1" -v var1="$var" 'BEGIN{print num,var1}') |
-f |
指定脚本文件(在命令行模式分割多个命令用分号;,在脚本文件中分割多个命令用换行符)(建议在脚本文件里写,不建议在命令行里写) |
-F |
指定分隔符 |
-V |
查看awk的版本号 |
[root@VM_0_13_centos ~]# num1=20
[root@VM_0_13_centos ~]# var="hello world"
[root@VM_0_13_centos ~]# awk 'BEGIN{print $num1}'
[root@VM_0_13_centos ~]# awk 'BEGIN{print $var}'
[root@VM_0_13_centos ~]# awk -v num=$num1 -v var1=$var 'BEGIN{print num,var1}'
awk: fatal: cannot open file `BEGIN{print num,var1}' for reading (No such file or directory)
[root@VM_0_13_centos ~]# awk -v num=$num1 -v var1="$var" 'BEGIN{print num,var1}'
20 hello world
[root@VM_0_13_centos ~]# awk -v num="$num1" -v var1="$var" 'BEGIN{print num,var1}'
20 hello world
# 指定脚本文件执行awk,脚本文件的书写格式
# 注意BEGIN、匹配模式以及END后面的大括号{,必须和BEGIN、匹配模式以及END在同一行
BEGIN{
printf "%-20s%-10s\n","IP","Count"
}
$0!~/^$/{
if($6!="Accepted")
{
ip_list[$11]+=1
}
}
END{
for(ip in ip_list)
{
printf "%-20s%-10d\n",ip,ip_list[ip]
}
}
awk中数组的用法
shell中数组的用法
array=("Allen" "Mike" "Messi" "Jerry" "Hanmeimei" "Wang")
打印元素 echo ${array[2]} # 下标从0开始
打印元素个数 echo ${#array[@]}
打印元素长度 echo ${#array[3]} # 求字符串长度${#str}
给元素赋值 array[3]="Li"
删除元素 unset array[2];unset array
分片访问 echo ${array[@]:1:3} # 从数组下标为1的开始,访问后面三个元素;如果3省略,那就直接访问到数组结尾
元素内容替换 ${array[@]/e/E} 只替换数组中每个元素内的第一个e; ${array[@]//e/E} 替换数组中每个元素内所有的e
数组遍历
for a in ${array[@]}
do
echo $a
done
# for a in ${array[@]}; do echo $a; done
awk中数组的用法
在awk中,使用数组时,不仅可以使用1.2…n作为数组下标(下标从1开始),也可以使用字符串作为数组下标
1.当使用1.2.3…n时,直接使用array[n]访问元素;需要遍历数组时,使用以下形式:
str="Allen Jerry Mike Tracy Jordan Kobe Garnet"
split(str,array," ")
# 第一种遍历形式
for(i=1;i<length(array);i++)
print array[i]
# 第二种遍历形式
for(i in array)
print array[i]
[root@VM_0_13_centos ~]# awk 'BEGIN{str="Allen Jerry Mike Tracy Jordan Kobe Garnet";split(str,array);for(i=1;i<length(array);i++) print array[i]}'
Allen
Jerry
Mike
Tracy
Jordan
Kobe
[root@VM_0_13_centos ~]# awk 'BEGIN{str="Allen Jerry Mike Tracy Jordan Kobe Garnet";split(str,array);for(a in array) print array[a]}'
Tracy
Jordan
Kobe
Garnet
Allen
Jerry
Mike
2.当使用字符串作为数组下标时,需要使用array[str]形式访问元素;遍历数组时,使用以下形式:
array["var1"]="Jin"
array["var2"]="Hao"
array["var3"]="Fang"
# 字符串作为数组下标的遍历形式,只有这一种
for(a in array)
print array[a]
[root@VM_0_13_centos ~]# awk 'BEGIN{array["var1"]="Jin";array["var2"]="Hao";array["var3"]="Fang";for(a in array){print array[a]}}'
Jin
Hao
Fang
典型常用例子
1.统计主机上所有的TCP连接状态数,按照每个TCP状态分类
# array[$6]++,使用$6这个字段的字符串作为数组的下标,值未定义默认为0,当遇到相同的字符串下标时,就对这个下标对应的数组中元素值加1,如果遇到不同的字符串下标,那就会以这个下标在数组中新增一个元素
[root@VM_0_13_centos ~]# netstat -an | grep tcp | awk '{array[$6]++}END{for(a in array) print a,array[a]}'
LISTEN 4
ESTABLISHED 2
TIME_WAIT 9
2.计算横向数据总和,计算纵向数据总和
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@VM_0_13_centos ~]# cat student.awk
BEGIN{
printf "%-10s%-10s%-10s%-10s%-10s%-10s\n","Name","YuWen","Math","English","Physical","Total"
}
{
total=$2+$3+$4+$5
yuwen_sum+=$2
math_sum+=$3
english_sum+=$4
physical_sum+=$5
printf "%-10s%-10d%-10d%-10d%-10d%-10d\n",$1,$2,$3,$4,$5,total
}
END{
printf "%-10s%-10d%-10d%-10d%-10d\n","",yuwen_sum,math_sum,english_sum,physical_sum
}
[root@VM_0_13_centos ~]# awk -f student.awk student.txt
Name YuWen Math English Physical Total
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
3.利用awk处理日志,并生成结果报告
生成数据脚本insert.sh,内容如下
#!/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
# $RANDOM is shell Built-in variable, it can generate a random number, range is [0, 32767]
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
数据格式如下:
2019-02-19 13:17:29 1 Batches: user allen insert 15145 records into database:product table:detail, insert 3995 records successfully, failed 11150 records
2019-02-19 13:17:29 2 Batches: user mike insert 8083 records into database:product table:detail, insert 3453 records successfully, failed 4630 records
2019-02-19 13:17:29 3 Batches: user jerry insert 31794 records into database:product table:detail, insert 9663 records successfully, failed 22131 records
2019-02-19 13:17:29 4 Batches: user tracy insert 24121 records into database:product table:detail, insert 21716 records successfully, failed 2405 records
1.统计每个人员分别插入了多少条record进数据库
输出结果:
USER TOTAL_RECORDS
allen 490990
mike 323339
[root@VM_0_13_centos awk]# cat db.awk
BEGIN{
printf "%-10s%-20s\n","USER","TOTAL_RECORDS"
}
{
user[$6]+=$8
}
END{
for(u in user)
{
printf "%-10s%-20d\n",u,user[u]
}
}
[root@VM_0_13_centos awk]# awk -f db.awk db.log.20190311
USER TOTAL_RECORDS
tracy 187533387
allen 188668476
mike 188232914
jerry 186532169
lilei 187869349
han 186615719
2.统计每个人分别成功插入了多少条记录,以及失败了多少条记录
[root@VM_0_13_centos awk]# cat db.awk
BEGIN{
printf "%-10s%-20s%-20s%-20s\n","USER","TOTAL_RECORDS","SUCCESS","FAILED"
}
{
user[$6]+=$8
user_success[$6]+=$14
user_failed[$6]+=$18
}
END{
for(u in user)
{
printf "%-10s%-20d%-20d%-20d\n",u,user[u],user_success[u],user_failed[u]
}
}
[root@VM_0_13_centos awk]# awk -f db.awk db.log.20190311
USER TOTAL_RECORDS SUCCESS FAILED
tracy 187533387 94745135 92788252
allen 188668476 93087694 95580782
mike 188232914 94174991 94057923
jerry 186532169 92814601 93717568
lilei 187869349 92863157 95006192
han 186615719 93822553 92793166
4.在例子3的基础上,加上结尾,统计全部插入记录数,成功记录数,失败记录数
[root@VM_0_13_centos awk]# cat db.awk
BEGIN{
printf "%-10s%-20s%-20s%-20s\n","USER","TOTAL_RECORDS","SUCCESS","FAILED"
}
{
user[$6]+=$8
user_success[$6]+=$14
user_failed[$6]+=$18
}
END{
for(u in user)
{
total+=user[u]
total_success+=user_success[$6]
total_failed+=user_failed[$6]
printf "%-10s%-20d%-20d%-20d\n",u,user[u],user_success[u],user_failed[u]
}
printf "%-20s%-20s%-20s\n","TOTAL","TOTAL_SUCCESS","TOTAL_FAILED"
printf "%-20d%-20d%-20d\n",total,total_success,total_failed
}
[root@VM_0_13_centos awk]# awk -f db.awk db.log.20190311
USER TOTAL_RECORDS SUCCESS FAILED
tracy 187533387 94745135 92788252
allen 188668476 93087694 95580782
mike 188232914 94174991 94057923
jerry 186532169 92814601 93717568
lilei 187869349 92863157 95006192
han 186615719 93822553 92793166
TOTAL TOTAL_SUCCESS TOTAL_FAILED
1125452014 558526164 573484692
5.查找丢失数据的现象,也就是成功+失败的记录数,不等于一共插入的记录数。找出这些数据并输出结果:
[root@VM_0_13_centos awk]# awk '{if($8!=$14+$18){print NR,$0}}' db.log.20190311
9 2019-03-11 21:33:39 9 Batches: user jerry insert 31131 records into database:product table:detail, insert 13966 records successfully, failed 1716 records
899 2019-03-11 21:33:44 899 Batches: user han insert 4638 records into database:product table:detail, insert 29611 records successfully, failed 1678 records