tail -f 然后在匹配字符串时退出

tail -f 然后在匹配字符串时退出

我正在尝试配置一个启动脚本,它将启动 tomcat,监视 catalina.out 中的字符串“Server startup”,然后运行另一个进程。我尝试了 tail -f 与 grep 和 awk 的各种组合,但尚未有任何效果。我遇到的主要问题似乎是在 grep 或 awk 匹配字符串后强制 tail 停止运行。

我已简化为以下测试用例。

test.sh is listed below:

#!/bin/sh    
rm -f child.out
./child.sh > child.out &
tail -f child.out | grep -q B

child.sh is listed below:

#!/bin/sh
echo A
sleep 20
echo B
echo C
sleep 40
echo D

我看到的行为是 grep 在 20 秒后退出,但 tail 还需要 40 秒才能停止。我明白为什么会发生这种情况 - tail 只有在写入时才会注意到管道已消失,而这只有在将数据附加到文件时才会发生。由于 tail 要缓冲数据并将 B 和 C 字符作为单个写入输出(我通过 strace 确认了这一点),情况变得更加复杂。我尝试使用在其他地方找到的解决方案来解决这个问题,例如使用 unbuffer 命令,但这没有帮助。

有谁知道如何让它按照我期望的方式工作吗?或者等待 Tomcat 成功启动的想法(考虑等待 TCP 端口知道它已经启动,但怀疑这会变得比我现在尝试做的更复杂)。我已经设法让它与 awk 一起工作,在 match 上执行“killall tail”,但我对这个解决方案并不满意。注意,我正在尝试让它在 RHEL4 上运行。

答案1

像这样吗?

mkfifo child.fifo
tail -f child.out > child.fifo &
pid=$!
grep -q B child.fifo && kill $pid

在全:

#!/bin/sh    
rm -f child.out
./child.sh > child.out &
mkfifo child.fifo
tail -f child.out > child.fifo &
pid=$!
grep -q B child.fifo && kill $pid
rm child.fifo

似乎在20秒内运行。

$ time ./test2.sh

real    0m20.156s
user    0m0.033s
sys     0m0.058s

更新

这种方法似乎也有效:

#!/bin/sh
rm -f child.out
./child.sh > child.out &
(tail -f child.out | grep -q B child.out)

如果你看到它有时立即退出,请尝试添加 sleep 1,即

#!/bin/sh
rm -f child.out
./child.sh > child.out &
sleep 1
(tail -f child.out | grep -q B child.out)

答案2

在一行上,将“do foo”替换为命令“

# 启动服务 tomcat6
# tail -f /var/log/tomcat6/catalina.out | awk '/服务器启动/{system("do foo"); exit 0}'

答案3

丢掉尾巴。由于您从空的 child.out 开始,因此您不需要它,并且(正如您所发现的)它使事情变得复杂。只需在睡眠循环中 grep 第一个实例即可。

until fgrep -q "Server startup" child.out; do sleep 1; done

如果您确实需要保留尾部,因为您并不总是从空的 catalina.out 开始,请将尾部放在循环内:

until tail child.out| fgrep -q "Server startup"; do sleep 1; done

相关内容