Question

I would like to know if it is possible to delete all the lines of a selected pattern except the last one. It is not so easy to explain, so I will make an example.

I have a text file with content similar to this:

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

I would like to have an alternation between "sent" and "received" messages, where the "sent" one is the last between the sent messages with the same letter. So I need an output like:

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

Is there some program that can do something like that? I can use either Ubuntu or Windows, or build a simple C/C++ application, if necessary.

Was it helpful?

Solution

Here's a simple way:

tac FILE | uniq -w 6 | tac

We:

  1. Reverse-print the file using tac (necessary for uniq to work right here).
  2. Weed out duplicate lines basing uniqueness on only the first 6 characters (thereby ignoring the incrementing number in parantheses). Only the first line of a set of duplicate lines is kept, which is why we have used tac.
  3. Then reverse-print the file again so it's in the order you want.

OTHER TIPS

Under linux, this can be a one-liner, for example in awk:

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

The exact syntax depends on your pattern. Here, I just use the first two words ($1 $2) of the line to determine whether a line should be skipped. The skipped lines ($0) are stored in a temporary which is printed when the pattern is different or at the END.

If it is okay to print the first line of a similar block instead of the last line, the script reduces to:

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

or you can use the even more succinct alternative:

uniq -w 6

which sorts out unique lines, but considering only the first 6 characters.

In C, something like this will do:

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);
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top