【问题标题】:remove duplicate lines in log file删除日志文件中的重复行
【发布时间】:2020-07-10 11:23:12
【问题描述】:

我正在尝试从重复的行中清理我的日志文件。 首先,我使用带有 uniq -d 标志的 sort 命令,它可以帮助我删除重复项,但没有解决我的问题。

sort pnum.log | uniq -d

排序命令的输出。

PNUM-1233: [App] [Tracker] Text
PNUM-1233: [App] [Tracker] Text
PNUM-1236: [App] [Tracker] Text ddfg   
PNUM-1236: [App] [Tracker] Text ddfg
PNUM-1234: [App] [Tracker] Tex 123  ssd
PNUM-1235: [App] [Tracker] Text 1dbg  
PNUM-1234: [App] [Tracker] Text 123 ssd vp

排序命令删除重复项,但不幸的是,我还需要删除具有重复 PNUM 的行,并在示例输出中只保留一个带有 longes 文本的唯一 PNUM,它将是“PNUM-1234:[App] [Tracker] Text 123 ssd vp”应该从文件中删除另外 2 行 PNUM-1234 行。这怎么可能实现?有没有类似sort之类的linux命令可以帮助我进行排序?

期望是:

PNUM-1233: [App] [Tracker] Text
PNUM-1236: [App] [Tracker] Text ddfg   
PNUM-1235: [App] [Tracker] Text 1dbg  
PNUM-1234: [App] [Tracker] Text 123 ssd vp

【问题讨论】:

  • 这怎么可能是 sort 命令的输出?输出未排序!
  • and expectation would be 为什么PNUM-1234: 行没有被删除?它在输出中出现了两次。

标签: linux bash awk sed


【解决方案1】:

sort | uniq -d 不会删除重复项,它会打印每批 重复的行之一。您可能应该改用 sort -u - 将删除重复项。

但要回答你提出的问题:

$ awk '{print length($0), $0}' file | sort -k1,1rn | awk '!seen[$2]++' | cut -d' ' -f2-
PNUM-1234: [App] [Tracker] Text 123 ssd vp
PNUM-1236: [App] [Tracker] Text ddfg
PNUM-1235: [App] [Tracker] Text 1dbg
PNUM-1233: [App] [Tracker] Text

第一个awk 命令只是在每行前面加上它的长度,因此随后的sort 可以将所有行排序为最长的,然后第二个awk 仅在第一次出现该键时输出该行字段值(现在是具有该键值的最长行),然后 cut 删除第一个 awk 添加的行长度。

按顺序:

$ awk '{print length($0), $0}' file
31 PNUM-1233: [App] [Tracker] Text
31 PNUM-1233: [App] [Tracker] Text
39 PNUM-1236: [App] [Tracker] Text ddfg
36 PNUM-1236: [App] [Tracker] Text ddfg
39 PNUM-1234: [App] [Tracker] Tex 123  ssd
38 PNUM-1235: [App] [Tracker] Text 1dbg
42 PNUM-1234: [App] [Tracker] Text 123 ssd vp
$
$ awk '{print length($0), $0}' file | sort -k1,1rn
42 PNUM-1234: [App] [Tracker] Text 123 ssd vp
39 PNUM-1234: [App] [Tracker] Tex 123  ssd
39 PNUM-1236: [App] [Tracker] Text ddfg
38 PNUM-1235: [App] [Tracker] Text 1dbg
36 PNUM-1236: [App] [Tracker] Text ddfg
31 PNUM-1233: [App] [Tracker] Text
31 PNUM-1233: [App] [Tracker] Text
$
$ awk '{print length($0), $0}' file | sort -k1,1rn | awk '!seen[$2]++'
42 PNUM-1234: [App] [Tracker] Text 123 ssd vp
39 PNUM-1236: [App] [Tracker] Text ddfg
38 PNUM-1235: [App] [Tracker] Text 1dbg
31 PNUM-1233: [App] [Tracker] Text
$
$ awk '{print length($0), $0}' file | sort -k1,1rn | awk '!seen[$2]++' | cut -d' ' -f2-
PNUM-1234: [App] [Tracker] Text 123 ssd vp
PNUM-1236: [App] [Tracker] Text ddfg
PNUM-1235: [App] [Tracker] Text 1dbg
PNUM-1233: [App] [Tracker] Text

如果同一键值的多行长度相同,您没有说要打印哪一行,所以上面只会随机输出其中一个。如果这是一个问题,那么您可以使用 GNU 排序并添加 -s 参数(用于 stable sort)或将命令行更改为 awk '{print length($0), NR, $0}' file | sort -k1,1rn -k2,2n | awk '!seen[$3]++' | cut -d' ' -f3- - 在这两种情况下都可以确保在这种冲突中的行输出将是第一个输入中存在的一个。

【讨论】:

    【解决方案2】:

    假设您已经删除了重复的行,您可以使用以下awk 语句仅打印基于第一列PUM-XXXX 的唯一行,但选择最长的行。

    awk -F":" '{ if (length($0)> length(to_print[$1])) {to_print[$1]=$0} } END { for (key in to_print) { print to_print[key] } }'
    

    因此,您必须创建一个数组to_print 来跟踪最大的行。最后,它将打印该数组。

    【讨论】:

      【解决方案3】:

      因为第一个字段似乎有恒定的字符数,您可以:

      uniq -w 10 file
      

      【讨论】:

      • 不是恒定的,9999 之后会增加 :)
      【解决方案4】:

      这些命令应该能够从您的 pnum.log 文件中删除具有重复/重复 PNUM 的行,只保留一个具有最长文本的唯一 PNUM,并保持它们的相对行顺序:

      cat pnum.log | awk -F":" '
      { if (length($0)> length(line[$1])) {line[$1]=NR":"$0} }
      END { for (key in line) { print line[key] } }
      ' | sort -t: -nk1 | cut -d: -f2-
      

      【讨论】:

        猜你喜欢
        • 2014-08-08
        • 1970-01-01
        • 2017-01-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多