我知道这个问题已经问了很多次了,但是请相信我,我已经尝试了很多建议。我想做的是 连续监视Tomcat服务器的日志文件以检测其启动。其基于此stack post
我已经对其进行了一点修改,以添加一个超时,这样即使文件中根本不存在该字符串也不会等待。 代码如下所示。
echo 0 > flag
timeout $DEPLOY_WAIT tail -n0 -F $TOMCAT_LOG | while read LOGLINE
do
[[ "${LOGLINE}" == *"INFO: Server startup in"* ]] && echo 1 > flag && pkill -P $$ timeout
done
x=$(cat flag)
if [ $x -ne 0 ];then
在这里您可以看到我正在写入标志文件,以检测尾部是否超时或在文件中找到匹配的字符串。 如果我将其更改为类似
的变量flag=0
timeout $DEPLOY_WAIT tail -n0 -F $TOMCAT_LOG | while read LOGLINE
do
[[ "${LOGLINE}" == *"INFO: Server startup in"* ]] && flag=1 && pkill -P $$ timeout
done
if [ $flag -ne 0];then
然后,变量标志的值始终为0。while循环中完成的更新丢失。我进行了一些研究,发现这是因为管道导致bash生成了一个新的子shell,并且参数从父级传递到子级,反之亦然。 post建议的解决方案 是在不使用管道的情况下重写东西
flag=0
while read LOGLINE;
do
[[ "${LOGLINE}" == *"INFO: Server startup in"* ]] && flag=1 && pkill -P $$ timeout
done <<< $(timeout $DEPLOY_WAIT tail -n0 -F $TOMCAT_LOG)
if [ $flag -ne 0];then
此解决方案的问题在于,仅在命令超时完成后才将数据提供给while循环[并且用于检测超时过程并杀死它的代码也会更改。但没关系,因此不包括在内],并且一旦字符串到达文件中,我就无法检测到该字符串。无论如何,脚本都会等待超时时间。我正在寻找一种将两者结合为一个优雅的解决方案的方法,而不是将文件用作标记。
答案 0 :(得分:1)
您尝试的解决方案的问题:
done <<< $(timeout $DEPLOY_WAIT tail -n0 -F $TOMCAT_LOG)
是您正在捕获timeout ...
作为字符串的$( )
命令的整个输出(这意味着它必须等待直到过程退出),并且然后将其作为此处字符串(使用<<<
)传递给循环。为了使循环在产生时能够处理输出,您需要模拟管道,如下所示:
done < <(timeout $DEPLOY_WAIT tail -n0 -F $TOMCAT_LOG)
这看起来很相似,但是细节上却大不相同。 <( )
部分称为进程替换-它将timeout ...
命令作为子进程运行,并有效地插入连接到该进程的stdout的命名管道的文件名。然后,生成的< pipename
部分使循环从该命名管道中读取。效果与常规管道几乎相同(如您初次尝试一样),只是没有将循环强制插入子外壳中。
答案 1 :(得分:1)
使用PIPESTATUS检查是否已达到超时。如果超时,则返回值为124。
$ timeout 1 sleep 2 | read
Terminated
$ echo $PIPESTATUS
124
$ timeout 2 sleep 1 | read
$ echo $PIPESTATUS
0
也不要杀死timeout
。如果孩子死了,它会自行终止。