Question Details

No question body available.

Tags

bash awk sed

Answers (5)

Accepted Answer Available
Accepted Answer
July 13, 2026 Score: 3 Rep: 569,005 Quality: High Completeness: 40%

Here's a solution I tested using awk version 20200816 on MacOS:

awk '
  BEGIN { dateline="" }
  /^2026-/ { dateline=$0 }
  ! /^2026-/ { if (dateline) { print dateline } ; print $0 ; dateline="" }
  END { if (dateline) { print dateline } }
' input.txt

The output matches what you described is your desired output.

Edit: Added the END clause to handle a case I forgot. Credit to the answer by M-- for this.

July 13, 2026 Score: 7 Rep: 36,148 Quality: Medium Completeness: 50%

The issue with your tac approach is that it collapses all timestamp groups into one. You need to track when a timestamp block ends. I would also avoid hard-coding 2026 as you might get dates from other years.

awk '/^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}/ { last=$0; next }
     { if (last!="") { print last; last="" }; print }
     END { if (last!="") print last }' file.txt

When a timestamp line is seen, store it in last and skip printing. When a non-timestamp line is seen, if there's a stored last it means the run just ended so print it, then print the current line. The END block handles the edge case where the file ends on a timestamp.

July 14, 2026 Score: 0 Rep: 19,120 Quality: Medium Completeness: 80%

Updated to handle comment:

In my scenario, if the last line was a timestamp, then I would not be interested in it`

The original approach (at end), assumed that the last of every run of lines matching the regex should be printed. To handle the case when such a run must be followed by a line that doesn't match the regex, we can flip the initial value of f so that it starts out false (zero):

tac file.txt | awk '/2026-/ ? !--f : (f=1)' | tac
  • reverse the file
  • loop over each line:
    • does line match regex?
      • yes: print line if it is first of a run after a line that didn't match the regex
        • --f decrements from 1 (0, -1, -2, ...) if the run follows a non-regex line, or from 0 (-1, -2, -3, ...) when f has never been set. its negation is true only when --f==0 which can only happen in the first of those two cases
      • no: (re)set f and print anyway
  • un-reverse the result

The tac approach needs to reset f when the regex does not match.

For example:

tac file.txt | awk '!( /^2026-/ ? f++ : (f=0) )' | tac
  • f is zero when program starts
  • does line match regex?
    • if so, increment f and return its previous value
      • value returned will only be zero after first increment (ie. after first regex match)
    • else, reset f and return zero
      • (for portability, assignment is in parentheses to avoid ambiguous parsing)
  • negate the returned value - if non-zero, print line

Or same logic but possibly easier to follow (also shorter):

tac file.txt | awk '/^2026-/ ? !f++ : !(f=0)' | tac
  • does line match regex?
    • yes: print it if this is the first time f has been incremented (since a reset)
    • no: reset f and print the line
July 14, 2026 Score: 0 Rep: 38,612 Quality: Medium Completeness: 60%

I would harness GNU AWK for this task using 2-pass approach, let file.txt content be

important information 1 important information 2 2026-07-10T11:12:31.013620-04:00
July 14, 2026 Score: 0 Rep: 59,533 Quality: Low Completeness: 40%

This might work for you (GNU sed):

sed -E '/^2026/{N;/^(.{4}).\n\1/D}' file

Set the extended regex option -E.

If the first 4 characters of a line begin 2026, append the next line.

If that line meets the criteria of a repeated one, delete the first and repeat.

N.B. The regex can be tightened up as desired e.g.

sed -E '/^....-..-.....:/{N;/^(.{13}).
\n\1/D}' file