为什么在RHEL上的Bash中使用“read -t”无法超时?

6

为什么在RHEL5或RHEL6上从管道读取数据时,read -t不会超时?

这是我在RHEL系统上从管道读取数据时无法超时的示例:

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

如果我没记错的话,read -t 3应该在三秒后超时?非常感谢!Chris
GNU bash, version 4.1.2(1)-release (x86_64-redhat-linux-gnu)

以防万一,您能否调用“alias”并仔细检查您的系统上是否将“read”别名为其他内容? - Frédéric Hamidi
你知道variable只会在执行read命令的子shell中设置,对吧?你的bash版本没有lastpipe选项,无法使管道的最后一个命令在当前shell中执行。 - chepner
我对变量不感兴趣,但是$?还是谢谢你的指点! - Chris
你的最终目标是查看logfile.log文件是否在最近3秒内更新了特定字符串? - chepner
@Chris,我猜想你即使接受了一个答案,仍然不知道为什么“-t 3”无法工作,我的理解正确吗? - nhed
显示剩余4条评论
3个回答

4
给出的 chenpner 的解决方案应该是可行的。
原因很简单,你的版本不能工作:当你像你这样构建一个管道时,数据从左到右流经管道。然而,当你的 read 超时时,左侧的程序将继续运行,直到它们注意到管道已经断开,而这只有在它们尝试写入管道时才会发生。
一个简单的例子是这样的:
cat | sleep 5

五秒钟后,管道将会被中断,因为sleep命令已经结束,但是cat命令会一直运行直到你按下回车键。

在你的情况下,也就是说,直到grep产生结果,即使超时了,你的命令也会继续运行。


2
虽然这不是对你具体问题的直接回答,但你需要运行类似以下的东西:
read -t 3 variable < <( tail -f logfile.log | grep "something" )

为了在管道完成后看到新设置的variable值,需要将其设为可见。请确认此操作是否按预期超时。
由于您只是使用read作为固定时间后退出管道的方式,因此不必担心variable的范围。但是,grep可能会在超时时找到匹配项,但由于其自身的内部缓冲而未打印出来。您可以使用--line-buffered选项禁用它(至少在GNU grep中)。
tail -f logfile.log | grep --line-buffered "something" | read -t 3

如果可用,另一个选择是使用timeout命令代替read

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

在这里,我们在3秒后杀死tail,并像通常一样使用grep的退出状态。

谢谢。几乎-当超时值到达时,read会退出,但始终带有代码142-即使grep实际上找到了它应该找到的内容。 - Chris
1
你可能想要使用 grep --line-buffered,这样 grep 可以在找到匹配项时立即输出。 - chepner

0

我现在没有 RHEL 服务器来测试你的脚本,但我敢打赌 read 正确地在超时时退出并按预期工作。尝试运行:

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

而且你可以确认这一点。


你是对的 - readread(0, 0x7fff306fc50f, 1) = ? ERESTARTSYS (To be restarted) --- SIGALRM (Alarm clock) @ 0 (0) --- 后退出,但进程仍然挂起。 - Chris

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接