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)
Chris
  • 1,410
  • 12
  • 21
  • Just in case, can you invoke `alias` and double-check that `read` is not aliased to something else on your system? – Frédéric Hamidi May 14 '13 at 15:11
  • 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. – chepner May 14 '13 at 15:25
  • I'm not interested in variable but $?. Thanks for a point anyway! – Chris May 14 '13 at 15:32
  • So your ultimate goal is to see if logfile.log has been updated with a specific string in the last 3 seconds? – chepner May 14 '13 at 15:41
  • 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. – Chris May 14 '13 at 15:45
  • @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. – Charles Duffy May 14 '13 at 15:55
  • @ChrisDodd: `lastpipe` was actually [added in 4.2 (see item t.)](http://tiswww.case.edu/php/chet/bash/NEWS). – chepner May 14 '13 at 15:56
  • @chepner -- oops, you're right. I guess the 'summary of bash 4 features' I was looking at combined multiple subversions. – Chris Dodd May 14 '13 at 16:10
  • @Chris am I correct is assuming that even though you accepted an answer you still don't know why `-t 3` didn't work? – nhed Mar 27 '15 at 16:25

3 Answers3

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.

mata
  • 67,110
  • 10
  • 163
  • 162
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.

chepner
  • 497,756
  • 71
  • 530
  • 681
  • 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. – Chris May 14 '13 at 15:43
  • 1
    You probably want to use `grep --line-buffered` so that `grep` outputs as soon as a match is found. – chepner May 14 '13 at 15:48
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.

olivecoder
  • 2,858
  • 23
  • 22
  • You are right - `read` exits after `read(0, 0x7fff306fc50f, 1) = ? ERESTARTSYS (To be restarted) --- SIGALRM (Alarm clock) @ 0 (0) ---` but process is still hanging. – Chris May 14 '13 at 15:34