我正在尝试配置一个启动脚本,它将启动 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