프로그램이 실행될 때마다 삭제되고 다시 생성되는 로그 파일에서 정보를 추출해야 합니다. 파일이 존재한다는 것을 (다시) 감지한 후, 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
어떤 값을 갖게 되는지, 상황이 정확히 어떤 것인지 알 수 없습니다.