I've made a Bash script to monitor some server log files for certain data and my method probably isn't the most efficient.One section specifically bugs me is that I have to write a newline to the monitored log so that the same line wont be read over continually.Feedback would be greatly appreciated!#!/bin/bashserverlog=/home/skay/NewWorld/server.logonlinefile=/home/skay/website/log/online.logofflinefile=/home/skay/website/log/offline.logindex=0# Creating the fileif [ ! -f $onlinefile ]; then    touch $onlinefile    echo Name                  Date            Time >> $onlinefilefiif [ ! -f $offlinefile ]; then    touch $offlinefile    echo Name                  Date            Time >> $offlinefilefi# Functionsfunction readfile {# Login Variablesloginplayer=`tail -1 $serverlog | grep [INFO] | grep joined the game | awk '{print $4}'`logintime=`tail -1 $serverlog | grep [INFO] | grep joined the game | awk '{print $2}'`logindate=`tail -1 $serverlog | grep [INFO] | grep joined the game | awk '{print $1}'`# Logout Variableslogoutplayer=`tail -1 $serverlog | grep [INFO] | grep left the game | awk '{print $4}'`logouttime=`tail -1 $serverlog | grep [INFO] | grep left the game | awk '{print $2}'`logoutdate=`tail -1 $serverlog | grep [INFO] | grep left the game | awk '{print $1}'`# Check for Player Login    if [ ! -z $loginplayer ]; then        echo $loginplayer          $logindate  $logintime >> $onlinefile        echo Player $loginplayer login detected >> $serverlog        line=`grep -rne $loginplayer $offlinefile | cut -d':' -f1`        if [ $line > 1 ]; then            sed -i $lined $offlinefile            unset loginplayer                    unset line        fi    fi# Check for Player Logout    if [ ! -z $logoutplayer ]; then        echo $logoutplayer         $logoutdate $logouttime >> $offlinefile        echo Player $loginplayer logout detected >> $serverlog        line=`grep -rne $logoutplayer $onlinefile | cut -d':' -f1`        if [ $line > 1 ]; then            sed -i $lined $onlinefile            unset logoutplayer            unset line        fi    fi}# Loopwhile [ $index -lt 100 ]; do    readfiledone
Bash log monitoring
bash;logging;awk
Your goal is to monitor $serverlog continuously, and update $onlinefile and $offlinefile accordingly.  The fact that you repeatedly close and reopen $serverlog is problematic, not only for performance reasons, but as you remarked, you risk processing the same line endlessly.  Therefore, your general strategy should be to keep the file open, like this:tail -f $serverlog | do_all_processing_hereNote that grep [INFO] doesn't do what you intend; instead, it matches lines that contain any of the characters I, N, F, or O.  You probably meant grep -F '[INFO]'  the -F causes grep to treat your pattern as a fixed string rather than a regular expression.  Then, your structure would be:tail -f $serverlog | grep -F '[INFO]' | do_more_processing_hereI'm going to guess that [INFO] would appear in the third field of your server log.  If so, the efficient solution would betail -f $serverlog | \while read date time severity player message ; do    case $severity in      \[INFO\])        case $message in          *joined the game*)            echo $player    $date  $time >> $onlinefile            sed -i -e $(                awk -v player=$player '$1 == player { print NR d;}' $offlinefile            ) $offlinefile            ;;          *left the game*)            echo $player    $date  $time >> $offlinefile            sed -i -e $(                awk -v player=$player '$1 == player { print NR d;}' $onlinefile            ) $onlinefile            ;;        esac # case $message        ;;    esac # case $severitydoneIt's also possible to skip awk and edit $offlinefile and $onlinefile directly withsed -i /^$player /d $offlinefilebut there could be a vulnerability if $player contained special characters such as .*.  A better solution, if you have GNU awk  4.1.0, isawk -v player=$player '$1 != player' -i inplace $offlinefileWith other versions of awk, you could use tempfile to help you perform the edit.