while 循环中 break 的奇怪行为

Strange behavior of break inside while loop

我正在尝试编写 bash 脚本来观察 catalina.out 日志文件。每次出现字符串 java.lang.OutOfMemoryError 时,它都应该重新启动 tomcat。

(我知道最好在 webapp 中找到错误,但 webapp 需要 运行 直到开发人员找到错误。所以这只是(希望)短时间的修补程序。 )

问题在于“break”在找到模式后不会立即离开 while 循环。下面有更多详细信息。

这里是脚本:

#!/bin/bash

LOGFILE=/var/log/catalina.out
LOCKFILE=/tmp/pointtest.lock

while [ /bin/true ]
do
  echo "Starting tail-Loop"
  tail -fn0 ${LOGFILE} | \
  while read line
  do
    echo "Inside tail-Loop"
    echo "$line" | grep "java.lang.OutOfMemoryError" > /dev/null
    if [ $? = 0 ]
    then
      echo "Error! java.lang.OutOfMemoryError"
      # here should be the command to restart tomcat

      break
    fi

  done
  echo "Left tail-Loop"

done

这是一个没有错误的测试输入文件(文件名:noErrors):

Something
Something
Something
Something
Anything
Something
Something
Do something
And so on
Anything
Something

这是一个测试输入文件(文件名:oomErrors),内存不足错误:

Something
Something
        java.util.concurrent.ExecutionException: java.lang.OutOfMemoryError: Java heap space
                at java.util.concurrent.FutureTask.report(FutureTask.java:122)
                at java.util.concurrent.FutureTask.get(FutureTask.java:192)
                at org.apache.catalina.core.ContainerBase.threadStart(ContainerBase.java:1276)
                at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessorMonitor.run(ContainerBase.java:1322)
                at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
                at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:308)
                at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access1(ScheduledThreadPoolExecutor.java:180)
                at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:294)
                at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
                at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
                at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
                at java.lang.Thread.run(Thread.java:748)
        java.lang.OutOfMemoryError: Java heap space
Something
Something
Anything
        java.lang.OutOfMemoryError: Java heap space
        java.lang.OutOfMemoryError: Java heap space
Something
Something
Do something
And so on
        java.lang.OutOfMemoryError: Java heap space
Anything
Something

第一个:

touch /var/log/catalina.out

然后启动脚本。

输出:

Starting tail-Loop

现在我正在执行以下命令:

cat noErrors >> /var/log/catalina.out

脚本的输出:

Inside tail-Loop
Inside tail-Loop
Inside tail-Loop
Inside tail-Loop
Inside tail-Loop
Inside tail-Loop
Inside tail-Loop
Inside tail-Loop
Inside tail-Loop
Inside tail-Loop
Inside tail-Loop
Inside tail-Loop

所以直到这里脚本按预期工作。

现在我正在执行以下命令:

cat oomErrors >> /var/log/catalina.out

脚本输出:

Inside tail-Loop
Inside tail-Loop
Inside tail-Loop
Error! java.lang.OutOfMemoryError

oomErrors 的前两行处理正确。然后脚本找到了 OOM 模式,但它没有离开 tail-while-loop。

然后我执行这个命令:

cat noErrors >> /var/log/catalina.out

脚本的输出:

Left tail-Loop
Starting tail-Loop

只有在这里它才离开了 tail-while 循环并重新启动了 tail-while 循环。

似乎在检测到第一行错误后它忽略了以下行并在 break 命令处停止。

所以我的问题是:为什么脚本在找到带有错误字符串的第一行后不立即离开 tail-while-loop,我该如何解决这个问题?

提前致谢:-)

稍微简化并消除 grep 的不必要的开销。

while : # : is a synonym for true
do echo "Starting tail-Loop"
   while read line
   do echo "Inside tail-Loop"
      case "$line" in
      *java.lang.OutOfMemoryError*) 
        echo "Error! java.lang.OutOfMemoryError"
        # restart tomcat here
        break
     ;;
     esac
   done < <( tail -fn0 ${LOGFILE} )
   echo "Left tail-Loop"
done