Why `read -t` is not timing out in bash on RHEL?
Asked Answered
E

3

6

Why read -t doesn't time out when reading from pipe on RHEL5 or RHEL6?

Here is my example which doesn't timeout on my RHEL boxes wile reading from the pipe:

tail -f logfile.log | grep 'something' | read -t 3 variable

If I'm correct read -t 3 should timeout after 3 seconds?

Many thanks in advance.

Chris

GNU bash, version 4.1.2(1)-release (x86_64-redhat-linux-gnu)
Elroy answered 14/5, 2013 at 15:1 Comment(9)
Just in case, can you invoke alias and double-check that read is not aliased to something else on your system?Demodulation
You are aware that variable will only be set in the subshell in which that read command executes, right? Your version of bash doesn't have the lastpipe option to make the last command of a pipeline execute in the current shell.Kenyakenyatta
I'm not interested in variable but $?. Thanks for a point anyway!Elroy
So your ultimate goal is to see if logfile.log has been updated with a specific string in the last 3 seconds?Kenyakenyatta
Yes, actually in 20 min ;) I need to submit file for processing and wait for a process to finish processing it. Unfortunately apart form looking into logs I don't have any other way of knowing if file was processed or not.Elroy
@ChrisDodd That's the case on RHEL6, but earlier in the question he indicates also trying to target RHEL5, which doesn't have bash 4.Affinal
@ChrisDodd: lastpipe was actually added in 4.2 (see item t.).Kenyakenyatta
@Kenyakenyatta -- oops, you're right. I guess the 'summary of bash 4 features' I was looking at combined multiple subversions.Casandra
@Elroy am I correct is assuming that even though you accepted an answer you still don't know why -t 3 didn't work?Fungible
K
2

While not a direct answer to your specific question, you will need to run something like

read -t 3 variable < <( tail -f logfile.log | grep "something" )

in order for the newly set value of variable to be visible after the pipeline completes. See if this times out as expected.


Since you are simply using read as a way of exiting the pipeline after a fixed amount of time, you don't have to worry about the scope of variable. However, grep may find a match without printing it within your timeout due to its own internal buffering. You can disable that (with GNU grep, at least), using the --line-buffered option:

tail -f logfile.log | grep --line-buffered "something" | read -t 3

Another option, if available, is the timeout command as a replacement for the read:

timeout 3 tail -f logfile.log | grep -q --line-buffered "something"

Here, we kill tail after 3 seconds, and use the exit status of grep in the usual way.

Kenyakenyatta answered 14/5, 2013 at 15:32 Comment(2)
Thanks. Almost- read exits when timeout value is reached but always with code 142 - even if grep actually finds what it was supposed to find.Elroy
You probably want to use grep --line-buffered so that grep outputs as soon as a match is found.Kenyakenyatta
E
4

The solution given by chepner should work.

An explanation why your version doesn't is simple: When you construct a pipe like yours, the data flows through the pipe from the left to the right. When your read times out however, the programs on the left side will keep running until they notice that the pipe is broken, and that happens only when they try to write to the pipe.

A simple example is this:

cat | sleep 5

After five seconds the pipe will be broken because sleep will exit, but cat will nevertheless keep running until you press return.

In your case that means, until grep produces a result, your command will keep running despite the timeout.

Emylee answered 14/5, 2013 at 15:50 Comment(0)
K
2

While not a direct answer to your specific question, you will need to run something like

read -t 3 variable < <( tail -f logfile.log | grep "something" )

in order for the newly set value of variable to be visible after the pipeline completes. See if this times out as expected.


Since you are simply using read as a way of exiting the pipeline after a fixed amount of time, you don't have to worry about the scope of variable. However, grep may find a match without printing it within your timeout due to its own internal buffering. You can disable that (with GNU grep, at least), using the --line-buffered option:

tail -f logfile.log | grep --line-buffered "something" | read -t 3

Another option, if available, is the timeout command as a replacement for the read:

timeout 3 tail -f logfile.log | grep -q --line-buffered "something"

Here, we kill tail after 3 seconds, and use the exit status of grep in the usual way.

Kenyakenyatta answered 14/5, 2013 at 15:32 Comment(2)
Thanks. Almost- read exits when timeout value is reached but always with code 142 - even if grep actually finds what it was supposed to find.Elroy
You probably want to use grep --line-buffered so that grep outputs as soon as a match is found.Kenyakenyatta
I
0

I dont have a RHEL server to test your script right now but I could bet than read is exiting on timeout and working as it should. Try run:

grep 'something' | strace bash -c "read -t 3 variable"

and you can confirm that.

Insecure answered 14/5, 2013 at 15:21 Comment(1)
You are right - read exits after read(0, 0x7fff306fc50f, 1) = ? ERESTARTSYS (To be restarted) --- SIGALRM (Alarm clock) @ 0 (0) --- but process is still hanging.Elroy

© 2022 - 2024 — McMap. All rights reserved.