删除重复的行

时间:2016-12-05 07:41:55

标签: linux bash awk

我需要一些帮助来改变破碎的日志,我从我的管理员处收到(不幸的是他们不会修复它)。 基本上,有时日志包含重复的第一列,如果另一列的值等于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

3 个答案:

答案 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