여러 파일의 끝을 grep

여러 파일의 끝을 grep

충돌한 응용 프로그램의 로그 파일(20-500)이 많이 있습니다. 모든 로그 파일은 애플리케이션의 단일 실행에서 생성됩니다. 즉, 각 스레드가 자체 파일에 쓰는 고도의 다중 스레드입니다. 하지만 로그는. (어떤 경우에는 각각 수백 MB가 될 수도 있습니다)

이제 스레드 중 하나가 충돌하고 충돌이 발생하면 로그 파일의 마지막 100줄 정도에 메시지를 씁니다. 때로는 스레드가 모두 정상적으로 종료되고 행이 기록되지 않는 경우도 있습니다.

충돌하는 애플리케이션을 실행하는 래퍼 스크립트는 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 

관련 정보