2

I'm working on a script to monitor log files from a couple of servers and email/txt alerts when certain keywords are shown. All is working well to this point by using:

tail -n 0 -f "$MS01_LOG_FILE" "$MS02_LOG_FILE" | while IFS= read -r line; do
#do some fun things here
done

Trouble is, sometimes the server hangs up doesn't output to the log file for quite some time, and I would like to be notified of a stalled log. Of course, my script will just sit at the read-line waiting for input. I need a sort of timer that runs in the background I suppose that can break from the read-line.

2
  • You can try ... | while true; do IFS= read -r -t 42 line; ... done
    – gollum
    Oct 31, 2018 at 15:36
  • @gollum, please post answers as answers (not as comments), so that they can be voted on and accepted
    – ilkkachu
    Oct 31, 2018 at 17:23

1 Answer 1

1

TL;DR

The following alternative should do the trick:

#!/bin/bash

MS01_LOG_FILE=/var/log/dmesg
MS02_LOG_FILE=/var/log/syslog

TIMEOUT=10  # modify to your liking

tail -n 0 -f "$MS01_LOG_FILE" "$MS02_LOG_FILE" | while :
do
    IFS= read -t $TIMEOUT -r line
    # do your funny things here
done

Details

First quoting from help read (see bash reference manual for the builtin command "read")

-t timeout
Cause read to time out and return failure if a complete line of input (or a specified number of characters) is not read within timeout seconds. timeout may be a decimal number with a fractional portion following the decimal point. This option is only effective if read is reading input from a terminal, pipe, or other special file; it has no effect when reading from regular files. If read times out, read saves any partial input read into the specified variable name. If timeout is 0, read returns immediately, without trying to read and data. The exit status is 0 if input is available on the specified file descriptor, non-zero otherwise. The exit status is greater than 128 if the timeout is exceeded.

Note that the exit status being greater than 128 for detecting a read timeout is not guaranteed between implementations (e.g. on my OS X's bash it is 1).

Now simply adding -t $TIMEOUT to your initial script provides only one part of the solution since the broken pipe won't be detected until anything gets emitted from the tail pipe.

Moving the read into a endless while loop solves that issue.

Depending on what you want to do instead of # do your funny things here you might now be confronted with the issue of escaping from that child process jail.

In that case check https://stackoverflow.com/questions/20558295/quit-from-pipe-in-bash

1
  • 1
    Also note that bash's read like AT&T ksh's uses the $TMOUT variable (even one coming from the environment!) as default timeout. Nov 1, 2018 at 12:56

You must log in to answer this question.

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