只保留重复模式的最后一行

时间:2014-01-27 12:13:13

标签: c ubuntu text lines

我想知道是否可以删除除最后一个之外的所选图案的所有行。解释起来并不容易,所以我会举一个例子。

我有一个内容与此类似的文本文件:

A sent (1)
A received (1)
B sent (1)
B sent (2)
B sent (3)
B received (1)

我希望在“已发送”和“已接收”消息之间进行更改,其中“已发送”消息是具有相同字母的已发送消息之间的最后一个消息。所以我需要一个输出:

A sent (1)
A received (1)
B sent (3)
B received (1)

是否有某些程序可以做类似的事情?我可以使用Ubuntu或Windows,或者在必要时构建一个简单的C / C ++应用程序。

3 个答案:

答案 0 :(得分:2)

这是一个简单的方法:

tac FILE | uniq -w 6 | tac

我们:

  1. 使用tac反向打印文件(uniq必须在此处工作)。
  2. 仅在前6个字符上删除基于唯一性的重复行(从而忽略了parantheses中的递增数字)。只保留一组重复行的第一行,这就是我们使用tac
  3. 的原因
  4. 然后再次反向打印文件,使其按您想要的顺序排列。

答案 1 :(得分:1)

在linux下,这可以是单行,例如awk

awk '$1 $2 != prev {if (buf) print buf} {prev = $1 $2; buf = $0} END {print buf}' mylog.txt

确切的语法取决于您的模式。在这里,我只使用该行的前两个单词($1 $2)来确定是否应该跳过一行。跳过的行($0)存储在临时中,当模式不同或END时打印。

如果可以打印类似块的第一行而不是最后一行,则脚本将缩减为:

awk '$1 $2 != prev; {prev = $1 $2}' mylog.txt

或者您可以使用更简洁的替代方案:

uniq -w 6

排序唯一的行,但只考虑前6个字符。

答案 2 :(得分:0)

在C中,这样的事情会发生:

bool isFirstSent = false;
bool isSecondSent = false;
char *firstLine = getLine(file); // getline returns a char array 
                                 // if a line exists and NULL otherwise 
if (strstr(firstLine, "sent"))
   isFirstSent = true;
char *secondLine = getLine(file);

while (secondLine)
{
   if (strstr(secondLine, "sent"))
      isSecondSent = true;
   else
      isSecondSent = false;
   if (isFirstSent != isSecondSent)
      printf("%s", firstLine);
   free(firstLine);
   isFirstSent = isSecondSent;
   firstLine = secondLine;
   secondLine = getLine(file);
}

free(firstLine);