我需要一些帮助来改变破碎的日志,我从我的管理员处收到(不幸的是他们不会修复它)。 基本上,有时日志包含重复的第一列,如果另一列的值等于null,我想删除。
这就是它的外观
datetime,auth_protocol,result,client,port,login
2016-07-15 09:34:52,www,PASS,111.222.333.444,5593,someAddress@domain.com
2016-07-15 09:34:52,www,PASS,111.222.333.444,NULL,someAddress@domain.com
2016-08-14 00:51:35,www,PASS,NULL,19509,someAddress@domain.com
2016-08-14 00:51:35,www,PASS,444.333.222.111,19509,someAddress@domain.com
2016-09-16 05:08:46,www,FAIL,123.456.789.222,45673,someAddress@domain.com
2016-09-16 15:35:55,www,FAIL,123.456.789.222,NULL,someAddress@domain.com
2016-09-17 17:10:01,www,FAIL,111.222.333.444,55516,someAddress@domain.com
如您所见,某些行重复了第一列(日期)。
我想做的是:
1:对于所有列,第一列是重复的,比较4或5列(IP或端口)
2:删除第4列或第5列中带有空值的重复行
这可能是正确的输出:
datetime,auth_protocol,result,client,port,login
2016-07-15 09:34:52,www,PASS,111.222.333.444,5593,someAddress@domain.com
2016-08-14 00:51:35,www,PASS,444.333.222.111,19509,someAddress@domain.com
2016-09-16 05:08:46,www,FAIL,123.456.789.222,45673,someAddress@domain.com
2016-09-16 15:35:55,www,FAIL,123.456.789.222,NULL,someAddress@domain.com
2016-09-17 17:10:01,www,FAIL,111.222.333.444,55516,someAddress@domain.com
我希望听起来很清楚; d
答案 0 :(得分:3)
你可以使用这个awk。
两次迭代文件。
杜鹃第一次计算
打印行不是欺骗行或第二行不包含NULL。
awk -F, 'NR==FNR{a[$1]++;next}a[$1]<2||$4$5!~/NULL/' file{,}
datetime,auth_protocol,result,client,port,login
2016-07-15 09:34:52,www,PASS,111.222.333.444,5593,someAddress@domain.com
2016-08-14 00:51:35,www,PASS,444.333.222.111,19509,someAddress@domain.com
2016-09-16 05:08:46,www,FAIL,123.456.789.222,45673,someAddress@domain.com
2016-09-16 15:35:55,www,FAIL,123.456.789.222,NULL,someAddress@domain.com
2016-09-17 17:10:01,www,FAIL,111.222.333.444,55516,someAddress@domain.com
答案 1 :(得分:2)
通过对日志文件进行两次迭代,您可以收集第一次迭代中的所有使用日期。如果在第二次迭代中已经使用了日期,则删除NULL日志:
$ awk -F, '$4$5 !~ /NULL/ {d[$1]=1}
NR == FNR { next }
!d[$1] || $4$5 !~ /NULL/' input.log input.log
第一次迭代d
会使用指定字段中不包含NULL
的行中的已用日期填充。
NR == FNR
仅适用于第一个迭代文件。
在第二次迭代中,如果第4列中的NULL
不包含5,则会打印行。或者d
不包含使用的日期。
答案 2 :(得分:1)
你可以使用数组在bash中使用短脚本解决方案一次性完成。 (根据文件的长度,您可能会发现awk
更快的双遍,但对于较大的文件,此版本可能是有利的)。该脚本只读取所有行,但延迟打印每行,直到它读取下一行,并对日期/时间进行比较,以确定是否存在可能的重复条目。如果日期/时间相等,则检查IP字段。如果IP为NULL
,则会跳过打印该行。
这只是众多方法中的一种。尝试使用您的数据:
在NULL
字段中为id
添加了修改测试
#!/bin/bash
fn="${1:-/dev/stdin}" ## read file or stdin
prevln="" ## previous line & prev and curr arrays of values
declare -a prev=( ' ' ' ' ' ' ' ' ' ' ' ' ' ' )
declare -a curr
declare -i iddup=0 ## flag marking duplicate in 'id' field
IFS=$' ,\t\n' ## add ',' to internal field separator
while read -r line || test -n "$line"; do ## read each line
curr=( $(echo $line) ) ## fill current array with values
## test prev date/time with curr date/time
if [ "${prev[0]}" = "${curr[0]}" -a "${prev[1]}" = "${curr[1]}" ]; then
if [ "${prev[4]}" != "NULL" ]; then ## if prev IP != NULL print
echo "$prevln" ## otherwise, skip print
fi
[ "${curr[5]}" = "NULL" ] && iddup=1 || iddup=0 ## flag id dup
elif [ "$iddup" -eq '0' ]; then ## if date/time inequal, print line
[ -n "$prevln" ] && echo "$prevln"
fi
prevln="$line" ## assign line to prevln
prev=( ${curr[@]} ) ## assign curr to prev array
done <"$fn"
## same test for the last line after loop exits
curr=( $(echo $line) )
if [ "${prev[0]}" = "${curr[0]}" -a "${prev[1]}" = "${curr[1]}" ]; then
if [ "${prev[4]}" = "NULL" ]; then
echo "$line"
elif [ "${curr[4]}" = "NULL" ]; then
echo "$prevln"
else
echo "$prevln"
fi
else ## if date/time inequal, print line
[ -n "$prevln" ] && echo "$prevln"
fi
输入文件
$ cat dat/log.txt
2016-07-15 09:34:52,www,PASS,111.222.333.444,5593,someAddress@domain.com
2016-07-15 09:34:52,www,PASS,111.222.333.444,NULL,someAddress@domain.com
2016-08-14 00:51:35,www,PASS,NULL,19509,someAddress@domain.com
2016-08-14 00:51:35,www,PASS,444.333.222.111,19509,someAddress@domain.com
2016-09-16 05:08:46,www,FAIL,123.456.789.222,45673,someAddress@domain.com
2016-09-16 15:35:55,www,FAIL,123.456.789.222,NULL,someAddress@domain.com
2016-09-17 17:10:01,www,FAIL,111.222.333.444,55516,someAddress@domain.com
示例使用/输出
$ bash logdups.sh <dat/log.txt
2016-07-15 09:34:52,www,PASS,111.222.333.444,5593,someAddress@domain.com
2016-07-15 00:51:35,www,PASS,444.333.222.111,19509,someAddress@domain.com
2016-09-16 05:08:46,www,FAIL,123.456.789.222,45673,someAddress@domain.com
2016-09-16 15:35:55,www,FAIL,123.456.789.222,NULL,someAddress@domain.com
2016-09-17 17:10:01,www,FAIL,111.222.333.444,55516,someAddress@domain.com