Grep -Q' Not Exiting with 'Tail -F'

grep -q' not exiting with 'tail -f'

tail -f will read a file and display lines later added, it will not terminate (unless a signal like SIGTERM is sent). grep is not the blocking part here, tail -f is. grep will read from the pipe until it is closed, but it never is because tail -f does not quit and keep the pipe open.


A solution to your problem would probably be (not tested and very likely to perform badly):

tail -f logfile | while read line; do
echo $line | grep -q 'find me to quit' && break;
done

Ending tail -f started in a shell script

The best answer I can come up with is this

  1. Put a timeout on the read, tail -f logfile | read -t 30 line
  2. Start tail with --pid=$$, that way it'll exit when the bash-process has finished.

It'll cover all cases I can think of (server hangs with no output, server exits, server starts correctly).

Dont forget to start your tail before the server.

tail -n0 -F logfile 2>/dev/null | while read -t 30 line

the -F will 'read' the file even if it doesn't exist (start reading it when it appears). The -n0 won't read anything already in the file, so you can keep appending to the logfile instead of overwriting it each time, and to standard log rotation on it.

EDIT:

Ok, so a rather crude 'solution', if you're using tail. There are probably better solutions using something else but tail, but I got to give it to you, tail gets you out of the broken-pipe quite nicely. A 'tee' which is able to handle SIGPIPE would probably work better. The java process actively doing a file system drop with an 'im alive' message of some sort is probably even easier to wait for.

function startServer() {
touch logfile

# 30 second timeout.
sleep 30 &
timerPid=$!

tail -n0 -F --pid=$timerPid logfile | while read line
do
if echo $line | grep -q 'Started'; then
echo 'Server Started'
# stop the timer..
kill $timerPid
fi
done &

startJavaprocess > logfile &

# wait for the timer to expire (or be killed)
wait %sleep
}

tail -f | grep in if statement

Your pipe (tail -f ... | grep ...) will never end.

Add -m 1 to your GNU grep to exit after first match.

How to 'grep' a continuous stream?

Turn on grep's line buffering mode when using BSD grep (FreeBSD, Mac OS X etc.)

tail -f file | grep --line-buffered my_pattern

It looks like a while ago --line-buffered didn't matter for GNU grep (used on pretty much any Linux) as it flushed by default (YMMV for other Unix-likes such as SmartOS, AIX or QNX). However, as of November 2020, --line-buffered is needed (at least with GNU grep 3.5 in openSUSE, but it seems generally needed based on comments below).

Do a tail -F until matching a pattern

Try this:

sh -c 'tail -n +0 -f /tmp/foo | { sed "/EOF/ q" && kill $$ ;}'

The whole command-line will exit as soon as the "EOF" string is seen in /tmp/foo.

There is one side-effect: the tail process will be left running (in the background) until anything is written to /tmp/foo.

Using tail in a subshell in conjunction with while/break does not exit the loop

Try this, although it's not quite the same (it doesn't skip the beginning of the log file at startup):

triggerwordfound=
while [ -z "$triggerwordfound" ]; do
while read line; do
echo $line
if echo $line|grep "${triggerword}";then
echo "Logout completion detected"
start_leaks_detection
triggerwordfound=true
echo "Leaks detection complete"
fi
done
done < "$logfile"
echo "Outside loop"

The double loop effectively does the same thing as tail -f.

Linux: Block until a string is matched in a file (tail + grep with blocking)

Thanks both for answers, but the important part was that the process blocks until found, then ends. I found this:

grep -q 'PATTERN' <(tail -f file.log)

-q is not much portable, but I will only use Red Hat Enterprise Linux so it's ok.
And with timeout:

timeout 180 grep -q 'PATTERN' <(tail -f file.log)


Related Topics



Leave a reply



Submit