Home > Back-end >  How do I prevent my bash script (tailing a file) from repeatedly acting on the same line?
How do I prevent my bash script (tailing a file) from repeatedly acting on the same line?

Time:04-27

I was working on a script that would keep monitoring login to my server or laptop via ssh.

this was the code that I was working with.

slackmessenger() {
curl -X POST -H 'Content-type: application/json' --data '{"text":"'"$1"'"}' myapilinkwashere 
## removed it the api link due to slack restriction
}

while true
do
        tail /var/log/auth.log | grep sshd | head -n 1 | while read LREAD
        do
        echo ${LREAD}
        var=$(tail -f /var/log/auth.log | grep sshd | head -n 1)
        slackmessenger "$var"
        done
done

The issue I'm facing is that it keeps sending the old logs due to the while loop. can there be a condition that the loop only sends the new entries/updated enter as opposed to sending the old one over and over again. could not think of a condition that would skip the old entries and only shows old one.

CodePudding user response:

Instead of using head -n 1 to extract a line at a time, iterate over the filtered output of tail -f /var/log/auth.log | grep sshd and process each line once as it comes through.

#!/usr/bin/env bash
#              ^^^^- this needs to be a bash script, not a sh script!
case $BASH_VERSION in '') echo "Needs bash, not sh" >&2; exit 1;; esac

while IFS= read -r line; do
  printf '%s\n' "$line"
  slackmessenger "$line"
done < <(tail -f /var/log/auth.log | grep --line-buffered sshd)

See BashFAQ #9 describing why --line-buffered is necessary.


You could also write this as:

#!/usr/bin/env bash
case $BASH_VERSION in '') echo "Needs bash, not sh" >&2; exit 1;; esac

tail -f /var/log/auth.log |
  grep --line-buffered sshd |
  tee >(xargs -d $'\n' -n 1 slackmessenger)
  •  Tags:  
  • bash
  • Related