How to monitor only the last n lines of a log file?

I have a growing log file for which I want to display only the last 15 lines. Here is what I know I can do:

tail -n 15 -F mylogfile.txt

As the log file is filled, tail appends the last lines to the display.

I am looking for a solution that only displays the last 15 lines and get rid of the lines before the last 15 after it has been updated. Would you have an idea?

It might suffice to use watch:

$ watch tail -n 15 mylogfile.txt
Answered By: William Pursell

You could stream the logfile running less and pressing SHIFT + F that will stream the file using less.
$ less mylogfile.txt
Then just press SHIFT + F and it will stream. I think it is convenient for monitoring log files that update.

Answered By: Niklas Rosencrantz

If you use watch, try the -n option to control the interval between each update.

Thus, the following would call tail every 2 seconds

$ watch -n 2 tail -n 15 mylogfile.txt

while this one polls it every 1 second

$ watch -n 1 tail -n 15 mylogfile.txt
Answered By: Turgon

Maybe you find the -d param handy.

man watch

-d
Highlight the differences between successive updates. Option will read optional argument that changes highlight to be
permanent, allowing to see what has changed at least once since first
iteration.

Answered By: michalzuber

In Solaris, AIX or HPUX or UNIX-like (including Linux) you can use scripts to monitoring logs or anything like that:

while true; 
    clear; 
    do date; 
    echo ;
    echo "MONITORING LOG IN "/path/to/file.log": "; 
    echo "Obs.: Last 20 lines of a logfile:
    echo ;
    tail -20 /path/to/file.log;
    echo ;
sleep 5; 
done
Answered By: João Gerardo

Old question, but I’ve decided to write myself a bash function that does exactly that. Pasting the script here for those who want it. "ntail" preserves the last N lines and has a timeout before updating the screen to minimize flickering effects when stdout updates too often.

You can try it out with the following example command, for which the screen updates should preserve the "date", but render a scrolling effect on the stdout of the for loop:

date; for i in $(seq 1 2000); do echo $i; sleep 0.03; done | ntail 10
#!/bin/bash
# Display last N lines of input like tail, but cleaning the screen before every update.
# Example: date; for i in $(seq 1 2000); do echo $i; sleep 0.03; done | ntail 10

function ntail {

    # default to 10 lines of tail output
    NUM_LINES=${1:-10}

    # gets the current time in milliseconds
    function mstime() {
        date +%s%3N
    }

    LAST_UPDATE=$(mstime)   # last time the screen was updated
    NEEDS_REFRESH=false     # whether to refresh the screen
    SCREEN_BUFFER_SIZE=0    # number of lines on the screen
    while IFS= read -r NEW_LINE; do

        # concatenate new the new line to the buffer
        TAIL_BUFFER="$TAIL_BUFFER$NEW_LINE"$'n'

        # if last update is greater than 100ms, refresh screen
        if [ $(($(mstime) - LAST_UPDATE)) -gt 100 ]; then
            NEEDS_REFRESH=true
        fi

        # refresh screen if needed
        if [ "$NEEDS_REFRESH" = true ]; then

            # reduce buffer size to last NUM_LINES lines
            TAIL_BUFFER=$(echo "$TAIL_BUFFER" | tail -n "$NUM_LINES")$'n'

            # clear the last SCREEN_BUFFER_SIZE lines, preserving the stdout above that
            for _ in $(seq 1 "$SCREEN_BUFFER_SIZE"); do
                printf "33[1A33[2K"
            done

            # print the new buffer
            printf "%s" "$TAIL_BUFFER"

            SCREEN_BUFFER_SIZE=$(echo "$TAIL_BUFFER" | wc -l)
            SCREEN_BUFFER_SIZE=$((SCREEN_BUFFER_SIZE - 1))
            LAST_UPDATE=$(mstime)
            NEEDS_REFRESH=false

        fi

    done < /dev/stdin
}

ntail "$@"

Answered By: TheMechanic
Categories: Answers Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.