삭제되고 다시 생성되는 로그 파일을 지속적으로 추적하는 방법은 무엇입니까?

삭제되고 다시 생성되는 로그 파일을 지속적으로 추적하는 방법은 무엇입니까?

프로그램이 실행될 때마다 삭제되고 다시 생성되는 로그 파일에서 정보를 추출해야 합니다. 파일이 존재한다는 것을 (다시) 감지한 후, tail정규 표현식과 함께 사용하고 싶습니다 .

정규식은 여러 번 일치하지만 결과는 항상 동일합니다. 한 번만 인쇄한 다음 파일이 다시 생성되면 조사식을 반환하고 싶습니다.

파일 생성을 감지하는 방법을 살펴보았습니다. 패스하는 것도 하나의 방법inotifywait, 그러나 이를 위해서는 별도의 패키지를 설치해야 합니다.

stderr아마도 더 간단한 접근 방식은 후행 파일을 삭제하고 생성할 때 후행 인쇄를 활용하는 것입니다 .

tail: '/path/to/debug.log' has become inaccessible: No such file or directory
tail: '/path/to/debug.log' has appeared;  following new file

그래서 신청했어요이 솔루션달리기:

debug_file="/path/to/debug.log"

while true; do
    # Monitor the log file until the 'new file' message appears
    ( tail -F $debug_file 2>&1 & ) | grep -q "has appeared;  following new file"
    
    # After the new file message appears, switch to monitoring for the regexp
    tail -F "$debug_file" | while read -r line; do
        id=$(echo "$line" | sed -n 's/.* etc \([0-9]\+\),.*/\1/p')
        if [ -n "$id" ]; then
            echo "ID: $id"
            break  # Exit the inner loop after the first match
        fi
    done
done

하지만 저는 두 가지 다른 프로세스를 시작하는 이 솔루션이 마음에 들지 않습니다 tail. 하나의 프로세스만 사용하여 동일한 결과를 얻을 수 있는 방법이 있습니까 tail?

그런 다음 "모드"를 전환하고 먼저 파일 생성을 찾은 다음 정규식을 찾은 다음 "대기" 모드로 돌아가 로그 파일이 삭제되고 다시 생성될 때까지 기다립니다.

inotifywait가 더 우아한 솔루션인가요? 이상적으로는 Windows CMD로 쉽게 이식할 수 있는 솔루션을 원합니다.

답변1

외부 루프가 필요하지 않은 것 같습니다. 테일 출력을 읽기로 파이프하면 두 가지 상태에 있는 상태 머신에서 작동할 수 있습니다. 일반적인 tail 상태와 새 파일 상태에서는 다음 일치 항목이 "ID:" 줄을 인쇄할 때까지 기다립니다.

그러나 읽을 때 stderr를 stdout으로 리디렉션하는 것이 좋습니다. 귀하의 예에 일부 의사 코드를 추가했습니다.

debug_file="/path/to/debug.log"

# After the new file message appears, switch to monitoring for the regexp
# state="new_file"
tail -F "$debug_file" 2>&1 | while read -r line; do
    # if state = "new_file"
        id=$(echo "$line" | sed -n 's/.* etc \([0-9]\+\),.*/\1/p')
        if [ -n "$id" ]; then
            echo "ID: $id"
            # state = "id_printed"
        fi
    # else
        # if line contains "has appeared;  following new file"
            # state = new_file
        # echo "$line"
    # fi
done

편집하다. 파일의 정규식에 일치하는 항목이 여러 개 있을 수 있고 첫 번째 항목만 일치시키려는 경우 위의 해결 방법을 사용해야 합니다. 그렇지 않으면 다소 복잡한 단일 라이너를 생성하게 될 수도 있습니다 tail -F | grep | sed(sed 대신 awk를 사용할 수도 있음). 요구 사항에 따라 -o 옵션을 사용하여 tail 및 grep만 사용하여 작업을 완료할 수도 있습니다.

예를 들어 tail -F /path/to/debug.log | grep -E '.* etc ([0-9]+),.*', 다음을 시도한 다음 거기에서 어떻게 변환할지 확인하세요.

답변2

사용TxR분명하지 않은 말투:

(open-tail "/path/to/debug.log")  ;; returns a stream that follows rotating log

예를 들어 다음을 사용하여 해당 스트림에서 입력을 읽습니다.

(with-stream (s (open-tail "/path/to/debug.log"))
  (whilet ((ln (get-line s)))
    (if-match `@nil etc @id,@nil` ln
      (put-line `ID: @id`))))

답변3

게임에서 파일을 지속적으로 추적해야 하는 유일한 줄과 출력은 다음과 같습니다.

tail -F "$debug_file" 2>/dev/null | awk '!seen[$0]++'

sed 명령의 regexp에 의해 생성된 행의 일부만 고려하려는 경우 sed -n 's/.* etc \([0-9]\+\),.*/\1/p'GNU awk의 3rg arg를 사용하여 이를 수행할 수 있습니다(테스트되지 않음)match()

tail -F "$debug_file" 2>/dev/null |
awk 'match($0,/.* etc ([0-9]+),/,a) && !seen[a[1]]++ { print "ID: " a[1] }'

또는 awk를 사용하십시오.

tail -F "$debug_file" 2>/dev/null |
awk '/.* etc [0-9]+,/ && sub(/.* etc /,"") && sub(/,.*/,"") && !seen[$0]++ { print "ID: " $0 }'

이전 입력 반복에서 표시된 "ID"를 삭제하려면 다음을 수행할 수 있습니다.

tail -F "$debug_file" 2>&1 |
awk '
    /^tail: \047.*\047 has appeared;  following new file$/ { delete seen }
    ... code from above ...
'

추적하려는 파일 자체에는 ^tail:.*이 정규식과 일치하는 행이 포함될 수 없다고 가정합니다.

이는 다음과 같을 가능성이 높습니다.

awk '/.* etc [0-9]+,/ && sub(/.* etc /,"") && sub(/,.*/,"") && !seen[$0]++ { print "ID: " $0 }'

이는 실제로 다음과 같이 보다 간결한 형식으로 작성할 수 있습니다.

awk '$(X-1) == "etc" && !seen[$X]++ { print "ID: " $X+0 }'

ID 번호가 포함된 공백으로 구분된 필드 번호는 어디에 있습니까 X? 하지만 로그 파일의 예를 보지 않고 이것이 작동하는지, 그렇다면 X어떤 값을 갖게 되는지, 상황이 정확히 어떤 것인지 알 수 없습니다.

관련 정보