【问题标题】:awk + filter Log filesawk + ​​过滤日志文件
【发布时间】:2014-07-22 22:03:51
【问题描述】:

我使用了以下不错的 awk 命令来过滤重复行

示例:

cat LogFile | awk '!seen[$0]++'

问题是在某些情况下我们需要过滤重复的行,尽管某些字段不同并且它们并不那么重要

例如

日志文件:

 [INFO],[02/Jun/2014-19:30:45],EXE,ds1a,INHT VERION , 1.4.4.3-08
 [INFO],[02/Jun/2014-19:31:25],EXE,ds1a,INHT VERION , 1.4.4.3-08
 [INFO],[02/Jun/2014-19:32:40],EXE,ds1a,INHT VERION , 1.4.4.3-08

请看一下这个文件 - LogFile

我需要从第三个分隔符“,”中删除重复的行,直到行尾,

不管第三个分隔符之前是什么

所以最后我应该得到这个过滤后的文件:(应该总是得到列表中的第一个)

    [INFO],[02/Jun/2014-19:30:45],EXE,ds1a,INHT VERION , 1.4.4.3-08

所以请帮我完成我的任务

如何从第三个分隔符“,”中过滤掉LofFile,并忽略以下字段:[INFO],[...........],EXE ,

备注——植入也可以用perl one liner line

【问题讨论】:

  • 这是一个糟糕的例子,因为所有的记录都是一样的。请说明您如何拥有仍然需要过滤掉的不同记录。
  • 请看更新问题,
  • @maihabunash 你还需要输出中的 3 个未引用字段吗?
  • 是的,正如问题所问,我想我会以任何方式安慰 Ed 的答案 - 他有很好的解决方案 -:)

标签: linux perl bash awk sed


【解决方案1】:

使用 GNU awk 进行 gensub():

$ awk '!seen[gensub(/([^,]*,){3}/,"","")]++' file
[INFO],[02/Jun/2014-19:30:45],EXE,ds1a,INHT VERION , 1.4.4.3-08

使用任何支持 RE 间隔的 awk(大多数现代 awk):

$ awk '{key=$0; sub(/([^,]*,){3}/,"",key)} !seen[key]++' file
[INFO],[02/Jun/2014-19:30:45],EXE,ds1a,INHT VERION , 1.4.4.3-08

【讨论】:

  • 啊,如果你多喝 1 杯咖啡,荣耀就属于你了 :-)。
  • 我有 5 个,但你仍然抢了我的风头! :P
  • 如果我没有去喝咖啡休息时间,我可能会更早地阅读这个问题:)
  • 你在这里所做的真是太棒了,哇——你应该得到一个很高的分数
  • 我希望会员们也为我投票-:)
【解决方案2】:

你可以拥有:

awk 'BEGIN{FS=OFS=","}{o=$0;$1=$2=$3=""}!seen[$0]++{print o;}' ...

【讨论】:

    【解决方案3】:

    使用 perl 单行:

    perl -lne '$k = s/(.*?,){3}//r; print if !$seen{$k}++' file.log
    

    输出:

    [INFO],[02/Jun/2014-19:30:45],EXE,ds1a,INHT VERION , 1.4.4.3-08
    

    说明:

    开关:

    • -l:启用行尾处理。 (仅当日志文件的最后一行缺少新行时才需要)
    • -n:为输入文件中的每一行创建一个 while(<>){..} 循环。
    • -e:告诉perl 在命令行上执行代码。

    代码:

    • $k = s/(.*?,){3}//r:保存变量$k中第三个逗号之后的所有内容
    • print if !$seen{$k}++:如果之前没有看到密钥,则打印该行。

    【讨论】:

    • 我愚蠢地尝试使用数组切片作为哈希的键。这不会像我那样工作。
    • 它可以在没有-l 的情况下工作,只要日志文件的最后一行没有丢失新行。
    • 是的,这行得通。但是$h{@a[2..4]} 只会使用计数作为键。是的,jaypal,我的大脑不喜欢unless,除非它在一个段落而不是代码中。 =)
    • @EdMorton 这是一个简单的sed 类替换。 ? 使其不是贪婪的,因此它不匹配超过 3 个文本逗号对,如花括号中指定的那样。 /r 修饰符返回修改后的字符串,而不是修改原始字符串。
    • @jaypal - 啊,我明白了,所以 ? 使前面的 RE 段匹配到第一个 , 之前,而不是在最后一个 , 之前。所以写.*?, 等同于写[^,]*, - 明白了! /r 这件事也很有意义。谢谢。
    【解决方案4】:

    使用自动拆分的方式略有不同:

    perl -aF, -ne'print unless $seen{"@F[3..$#F]"}++' logfile.txt
    

    【讨论】:

    • 我喜欢使用-aF,的切换风格。可能更倾向于-F/,/,但将它们分组到相关开关是传达意图的好选择。
    • @Miller:我理解您的偏好,但-F 选项非常好。如果您使用-Fx 或-F/x/,那么它将为您使用split(/x/, $_, 0)。所以-F, 做了split(/,/, $_, 0),但神奇的是-F/ 做了split(m[/], $_, 0),所以他们想了很多。此外,使用-F/x/ 似乎不符合单线的整个想法。我恨透了他们,但如果你抛弃了strict 和warnings,为什么还要坚持any 标准呢?
    • @Miller:另外,-aFx 和-Fx 一样,可以节省更多按键
    • 做一点自我分析,我认为我对-F// 格式的轻微依恋源于始终尝试使用split // 而不是split '',因此代码自我将该表达式记录为模式,而不仅仅是文字字符串。但是,我同意较短的格式有其好处,因此您可能会不时在我的一些单行中看到它。 :)
    • @Miller:我同意你关于split的第一个参数,因为split / /需要不同于split ' '。但是后者的命令行等价物是一个简单的-a,根本没有-F,所以我认为规则不会转移
    猜你喜欢
    • 1970-01-01
    • 2021-03-29
    • 2016-03-22
    • 1970-01-01
    • 1970-01-01
    • 2022-11-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多