删除部分重复的连续行但保留第一个和最后一个

ath*_*ats 7 sed awk text-processing

我有一个带有时间戳和每行六个值的日志文件,我想通过删除具有相同值的连续行(忽略时间戳)并保留每个重复集的第一行和最后一行来减少数据量。最好使用 bash 脚本。它应该是一个魔法sedawk命令组合。

即使我必须多次解析文件,一次读取 3 行并删除中间的一行,也是一个很好的解决方案。

原始文件:

1447790360      99999   99999   20.25   20.25   20.25   20.50
1447790362      20.25   20.25   20.25   20.25   20.25   20.50
1447790365      20.25   20.25   20.25   20.25   20.25   20.50
1447790368      20.25   20.25   20.25   20.25   20.25   20.50
1447790371      20.25   20.25   20.25   20.25   20.25   20.50
1447790374      20.25   20.25   20.25   20.25   20.25   20.50
1447790377      20.25   20.25   20.25   20.25   20.25   20.50
1447790380      20.25   20.25   20.25   20.25   20.25   20.50
1447790383      20.25   20.25   20.25   20.25   20.25   20.50
1447790386      20.25   20.25   20.25   20.25   20.25   20.50
1447790388      20.25   20.25   99999   99999   99999   99999
1447790389      99999   99999   20.25   20.25   20.25   20.50
1447790391      20.00   20.25   20.25   20.25   20.25   20.50
1447790394      20.25   20.25   20.25   20.25   20.25   20.50
1447790397      20.25   20.25   20.25   20.25   20.25   20.50
1447790400      20.25   20.25   20.25   20.25   20.25   20.50
Run Code Online (Sandbox Code Playgroud)

想要的结果:

1447790360      99999   99999   20.25   20.25   20.25   20.50
1447790362      20.25   20.25   20.25   20.25   20.25   20.50
1447790386      20.25   20.25   20.25   20.25   20.25   20.50
1447790388      20.25   20.25   99999   99999   99999   99999
1447790389      99999   99999   20.25   20.25   20.25   20.50
1447790391      20.00   20.25   20.25   20.25   20.25   20.50
1447790394      20.25   20.25   20.25   20.25   20.25   20.50
1447790400      20.25   20.25   20.25   20.25   20.25   20.50
Run Code Online (Sandbox Code Playgroud)

gao*_*the 5

uniq 是(某种程度上)完美的工具,默认情况下,在 uniq 中,您可以保留/显示集合中的第一行但不是最后一行。

uniq 有一个 -f 标志,允许您跳过前几个字段。

来自 man uniq:

   -f, --skip-fields=N
          avoid comparing the first N fields

   -s, --skip-chars=N
          avoid comparing the first N characters

   A field is a run of blanks (usually spaces and/or TABs), then non-blank characters.  Fields are skipped before chars.
Run Code Online (Sandbox Code Playgroud)

使用 uniq -c 显示计数的示例查看 uniq 正在做什么:

-bash-4.2$ uniq -c -f 1 original_file
  1 1447790360      99999   99999   20.25   20.25   20.25   20.50
  9 1447790362      20.25   20.25   20.25   20.25   20.25   20.50
  1 1447790388      20.25   20.25   99999   99999   99999   99999
  1 1447790389      99999   99999   20.25   20.25   20.25   20.50
  1 1447790391      20.00   20.25   20.25   20.25   20.25   20.50
  3 1447790394      20.25   20.25   20.25   20.25   20.25   20.50
Run Code Online (Sandbox Code Playgroud)

不错。非常接近想要的。而且很容易做到。但缺少 group 中的最后一个匹配行。。。。

uniq 中的分组选项对于这个问题也很有趣。。。

   --group[=METHOD]
          show all items, separating groups with an empty line METHOD={separate(default),prepend,append,both}

   -D, --all-repeated[=METHOD]
          print all duplicate lines groups can be delimited with an empty line METHOD={none(default),prepend,separate}
Run Code Online (Sandbox Code Playgroud)

例如,uniq by group 。。。

    -bash-4.2$ uniq --group=both -f 1 original_file 

1447790360      99999   99999   20.25   20.25   20.25   20.50

1447790362      20.25   20.25   20.25   20.25   20.25   20.50
1447790365      20.25   20.25   20.25   20.25   20.25   20.50
1447790368      20.25   20.25   20.25   20.25   20.25   20.50
1447790371      20.25   20.25   20.25   20.25   20.25   20.50
1447790374      20.25   20.25   20.25   20.25   20.25   20.50
1447790377      20.25   20.25   20.25   20.25   20.25   20.50
1447790380      20.25   20.25   20.25   20.25   20.25   20.50
1447790383      20.25   20.25   20.25   20.25   20.25   20.50
1447790386      20.25   20.25   20.25   20.25   20.25   20.50

1447790388      20.25   20.25   99999   99999   99999   99999

1447790389      99999   99999   20.25   20.25   20.25   20.50

1447790391      20.00   20.25   20.25   20.25   20.25   20.50

1447790394      20.25   20.25   20.25   20.25   20.25   20.50
1447790397      20.25   20.25   20.25   20.25   20.25   20.50
1447790400      20.25   20.25   20.25   20.25   20.25   20.50
Run Code Online (Sandbox Code Playgroud)

然后 grep 查找每个空行之前和之后的行并去除空行:

-bash-4.2$ uniq --group=both -f 1 original_file |grep -B1 -A1 ^$ |grep -Ev "^$|^--$"
1447790360      99999   99999   20.25   20.25   20.25   20.50
1447790362      20.25   20.25   20.25   20.25   20.25   20.50
1447790386      20.25   20.25   20.25   20.25   20.25   20.50
1447790388      20.25   20.25   99999   99999   99999   99999
1447790389      99999   99999   20.25   20.25   20.25   20.50
1447790391      20.00   20.25   20.25   20.25   20.25   20.50
1447790394      20.25   20.25   20.25   20.25   20.25   20.50
1447790400      20.25   20.25   20.25   20.25   20.25   20.50
Run Code Online (Sandbox Code Playgroud)

哒哒哒!不错。

  • 我知道这个答案已经很晚了:-7。我很惊讶这里的答案中没有提到 uniq。我喜欢 awk、sed 和 perl 的答案,但 uniq 可能是适合这里工作的工具。 (2认同)