7

I would like use a program like tail to follow a file as it's being written to, but not display the most recent lines.

For instance, when following a new file, no text will be displayed while the file is less than 30 lines. After more than 30 lines are written to the file, lines will be written to the screen starting at line 1.

So as lines 31-40 are written to the file, lines 1-10 will be written to the screen.

If there is no easy way to do this with tail, maybe a there's a way to write to a new file a prior line from the first file each time the first file is extended by a line, and the tail that new file...

2
  • 2
    I'm not sure what you mean. When line 31 is written you want line 1 to be printed? So you want a delay? That's not what tail does.
    – pipe
    Commented Apr 3, 2019 at 14:58
  • 1
    This question has a great title, but the explanation doesn't match. I am looking for how to follow a file without displaying the most recent lines at the point of running the command. i.e. follow the file but without outputting any lines until additional lines are added after the tail command is executed.
    – Rebroad
    Commented Dec 27, 2019 at 20:37

4 Answers 4

8

Same as @muru's but using the modulo operator instead of storing and deleting:

tail -fn+1 some/file | awk -v n=30 '
   NR > n {print s[NR % n]}
   {s[NR % n] = $0}
   END{for (i = NR - n + 1; i <= NR; i++) print s[i % n]}'
0
7

Maybe buffer with awk:

tail -n +0 -f some/file | awk '{b[NR] = $0} NR > 30 {print b[NR-30]; delete b[NR-30]} END {for (i = NR - 29; i <= NR; i++) print b[i]}'

The awk code, expanded:

{
    b[NR] = $0 # save the current line in a buffer array
}
NR > 30 { # once we have more than 30 lines
    print b[NR-30]; # print the line from 30 lines ago
    delete b[NR-30]; # and delete it
}
END { # once the pipe closes, print the rest
    for (i = NR - 29; i <= NR; i++)
        print b[i]
}
4
  • This works, but form the script I would expect it to work like tail, printing out a previous line as each new line is added to the file. Instead it prints out in spurts of ~70 lines after ~100 lines are added to the file. It does not print the most recent 30 lines, so it's pretty close...
    – ridthyself
    Commented Apr 3, 2019 at 2:25
  • 1
    @ridthyself if you have GNU awk, try adding a fflush(); after the print b[NR-30];. Maybe the output is being buffered.
    – muru
    Commented Apr 3, 2019 at 2:35
  • 2
    @ridthyself, your awk must be mawk, Try switching to gawk or pass the -W interactive option. Commented Apr 3, 2019 at 3:31
  • 1
    Once I switched to gawk, it worked perfectly. Thank you! Using tmux to split my wide screen into two columns, I can log the terminal to a file using script, then use this code in the other window to create an console overflow window -- works like a dream.
    – ridthyself
    Commented Apr 4, 2019 at 22:02
3

This isn't very efficient, because it will re-read the file two seconds after reading it last time, and you will miss lines if the output is coming too fast, but will otherwise do the job:

watch 'tail -n40 /path/to/file | head -n10'
3
  • 1
    What would thi behaviour of this look like if the file takes more than 2 seconds to read?
    – Darren H
    Commented Apr 3, 2019 at 6:10
  • 1
    @DarrenH With watch --precise, I'm not sure, but I would guess it runs the command back-to-back. With plain watch, it should run the tail/head pipe, wait two seconds, run it again, wait another two seconds, and so on.
    – user
    Commented Apr 3, 2019 at 14:54
  • 1
    Will this meet OP's requirements if more than 30 lines are added to the file per watch interval?
    – user
    Commented Apr 3, 2019 at 14:56
3

It depends on how the file you're tailing, but I think you can do this most simply with the following:

tail -n0 -F path/to/my/file.log

When you run the above, you'll only get the latest added lines if the process is appending lines to the end of the file (e.g., ./run_process.sh >> file.log), as most apps do to log files.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .