grep 多个文件的末尾

grep 多个文件的末尾

我从崩溃的应用程序中获得了许多日志文件(20-500)。所有日志文件都来自应用程序的一次运行 - 它是高度多线程的,每个线程都写入自己的文件。但日志是大的。 (在某些情况下,每个可能是数百 MB)

现在,其中一个线程崩溃了,当它崩溃时,它会将一条消息写入其日志文件的最后一百行左右。有时线程都完成正常并且该行从未被写入。

我运行崩溃应用程序的包装脚本位于 bash 中,我想检测应用程序何时以这种方式崩溃,以便我可以重新启动它。我能做比以下更好的事情吗:

# We want to run at least once
CRASHED=1
while [ CRASHED -eq 1 ]
    # Run the app
    run_application
    # Check the end of all the logs for KEY
    CRASHED=0
    for x in logs/* ; do
      if tail -n 100 $x | grep "KEY" ; then
        CRASHED=1
        # We'll only find it once, so may as well bail out now
        break
      fi
    done
done  

我主要感兴趣的是是否可以用内置的东西替换日志文件上的循环。我不能只使用

grep "KEY" logs/* 

因为文件太大,效率不高。

答案1

使用;

tail --follow -n 100 *.log | grep -q key

如果应用程序实际上在崩溃时退出,则省略 --follow 。 https://linux.die.net/man/1/tail

答案2

由于您已经能够暂停直到应用程序退出,因此您可以仅搜索最近修改过日志文件。您可以按数量或时间进一步限制此集合。

以下是一些假设日志文件名相当合理的替代解决方案。

  1. 假设日志文件名不包含空格,并且崩溃消息写入最后几 (6) 个文件之一中的某个位置:

    if grep -q "KEY" $(ls -dt logs/* | head -6)
    then echo FOUND; else echo NOT FOUND
    fi
    
  2. 假设日志文件名可能包含空格,但崩溃消息写入最后写入的几 (6) 个文件之一

    ls -t logs | head -6 | (
        while IFS= read -r f
        do
            grep -q "KEY" logs/"$f" && break
        done
        exit 1
    )
    if [[ $? -eq 0 ]]; then echo FOUND; else echo NOT FOUND; fi
    
  3. 假设日志文件名可能包含空格,但崩溃消息写入最后几 (6) 个写入的文件之一的最后部分(400 行)

    ls -t logs | head -6 | (
        while IFS= read -r f
        do
            tail -n400 logs/"$f" | grep -q "KEY" && break
        done
        exit 1
    )
    if [[ $? -eq 0 ]]; then echo FOUND; else echo NOT FOUND; fi
    
  4. 假设日志文件名不包含空格,并且崩溃消息写入最近几 (5) 分钟内写入的文件之一

    if grep -q "KEY" $(find logs -type f -min -5)
    then echo FOUND; else echo NOT FOUND
    fi
    
  5. 假设日志文件名可能包含空格,但崩溃消息写入最近几 (5) 分钟内写入的文件之一

    find logs -type f -min -5 | (
        while IFS= read -r f
        do
            grep -q "KEY" "$f" && break
        done
        exit 1
    )
    if [[ $? -eq 0 ]]; then echo FOUND; else echo NOT FOUND; fi
    
  6. 假设日志文件名可能包含空格,但崩溃消息写入最近几 (5) 分钟写入的文件的最后部分(400 行)

    find logs -type f -min -5 | (
        while IFS= read -r f
        do
            tail -n400 "$f" | grep -q "KEY" && break
        done
        exit 1
    )
    if [[ $? -eq 0 ]]; then echo FOUND; else echo NOT FOUND; fi
    

答案3

最后我采用了评论中的一些方法。将尾部从核心循环中取出可以进一步简化逻辑:我最终得到的是这样的:

while true
    echo "Starting the application"
    run_application
    echo "Application exited - checking logs for KEY"
    if ! tail -qn 100 logs/* | grep -q "KEY"
    then
      echo "Failed without KEY in the logs - exiting"
      break
    fi
    echo "Failed with KEY in the logs - restarting"
done 

相关内容