점진적으로 파일 읽기

점진적으로 파일 읽기

마지막으로 읽은 이후 업데이트된 파일의 일부를 읽어야 하는 요구 사항이 있습니다. 즉, 마지막으로 2016-07-26T01:30에 파일을 읽은 다음 100개의 레코드가 파일에서 업데이트되는 2016-07-26T02:30에 다시 실행하려면 Get을 읽어야 합니다. 이 100개 레코드의 전체 파일입니다.

파일 형식은 다음과 같습니다.

[2016-07-26T16:26:31.953-04:00] [AnalyticProviderServices0] [ERROR] [] [oracle.EPMOHPS] [tid: 17] [userId: <anonymous>] [ecid: 0000LGXnLUEComOpyg4EyW1N4iIi000002,1:28342] [APP: APS#11.1.2.0] Unable to resolve 'jdbc.EPMSystemRegistry'. Resolved 'jdbc'[[
[2016-07-26T16:26:31.954-04:00] [AnalyticProviderServices0] [WARNING] [] [oracle.EPMOHPS] [tid: 17] [userId: <anonymous>] [ecid: 0000LGXnLUEComOpyg4EyW1N4iIi000002,1:28342] [APP: APS#11.1.2.0] Failure while getting the active Essbase node for cluster [SWESSPROD1]. Runtime Provider Services Error: [Unable to resolve 'jdbc.EPMSystemRegistry'. Resolved 'jdbc']

답변1

로그 파일이 실행될 때마다 로그 파일을 점진적으로 읽는 Re-Tail 또는 "retail"이라는 명령줄 유틸리티(2003년부터)가 있습니다.

예를 들어 이는 매시간 실행되는 크론 작업에 유용합니다.

Re-Tail은 실행되는 각 파일에 대해 "오프셋 파일"에 상태를 저장하며 마지막 줄 번호와 해당 줄 번호에 텍스트를 저장합니다.

다음에 프로그램이 실행되면 저장된 줄 번호를 찾고 내용을 비교하려고 시도합니다. 일치하는 항목이 있으면 다음 줄부터 시작하여 파일의 나머지 부분을 출력합니다. 디스크에 있는 파일의 행 수가 적거나 행 내용이 일치하지 않는 경우 파일이 지워지거나 회전된 것으로 간주되며, 이 경우 첫 번째 행부터 시작됩니다.

마지막으로 Retail에서는 저장된 줄 번호와 내용을 업데이트합니다.

소프트웨어는 다음 위치에 있습니다.http://xjack.org/retail/

저는 Retail을 루트로 실행할 때 저장된 상태를 /var/lib/retail에 저장하는 것을 좋아합니다. 예를 들어, 한 컴퓨터에서는 SSH 로그인에 대한 보고서를 생성하기 위해 다음 명령줄이 포함된 스크립트를 사용하여 매시간 소매를 실행합니다.

/usr/local/bin/retail -p /var/lib/retail/ /var/log/secure >"$tempfile"

행운을 빌어요!

답변2

파일을 열어 둘 수 있습니다.

exec 3< file
cat <&3

sleep 3600

echo After one hour, these records were added:
cat <&3

cat이는 이러한 1시간을 호출하는 프로세스와 동일해야 함을 의미합니다.


파일 시스템에서 액세스 시간이 활성화되어 있고 스크립트가 파일을 읽는 유일한 스크립트인 경우 마지막 액세스 시간 이후의 타임스탬프가 있는 줄을 읽을 수도 있습니다. GNU 시스템에서:

awk -v last_access="$(find file -prune -printf %AFT%AT)" '
   $0 > last_access' < file

-04:00로그 파일의 오프셋은 현재 시간대에 해당한다고 가정합니다 .


또 다른 방법은 다음과 같은 어딘가에 현재 파일 위치를 기록하는 것입니다 file.pos.

{
   if [ -e file.pos ]; then
     pos=$(cat file.pos)
   else
     pos=0
   fi
   tail -c +"$((pos+1))"
   perl -le 'print tell STDIN' > file.pos
} < file

또는ksh93

{
   if [ -e file.pos ]; then
     pos=$(<file.pos)
   else
     pos=0
   fi
   cat <#((pos))
   exec <#((pos=CUR))
   echo "$pos" > file.pos
} < file

또는 다음을 사용하여 zsh:

zmodload zsh/system    
{
   if [ -e file.pos ]; then
     pos=$(<file.pos)
   else
     pos=0
   fi
   sysseek $pos
   cat
   echo "$((systell(0)))" > file.pos
} < file

답변3

#!/bin/bash

logfile="$1"

test -f "$logfile" || exit 1

lastline="$( basename "$logfile" )-last"

if [ -f "$lastline" ]; then
    place=$( <"$lastline" )
else
    place=1
fi

tmpfile="$( mktemp )"
trap 'rm -f "$tmpfile"' EXIT

sed -n -e "$place,\$p" -e '$=' "$logfile" |
tee "$tmpfile" |
tail -n 1 >"$lastline"

sed '$d' "$tmpfile"

이 작은 스크립트는 명령줄에서 로그 파일을 가져와 마지막으로 스크립트를 사용한 이후 추가된 모든 줄을 표시합니다. 현재 로그 파일 회전 형식을 이해하지 못합니다....-last이므로 로그가 순환되는 경우 현재 디렉터리에 생성된 파일을 수동으로 삭제해야 합니다.

할 수 있는 작업:

sed처음 실행하면 주어진 로그 파일의 모든 줄을 임시 파일로 출력하고 마지막 줄의 줄 번호를 출력하는 데 사용됩니다 . 번호는 로그 파일과 이름이 같고 접미사 가 -last. less필요한 경우 스크립트에 출력이 터미널로 전송됩니다). 스크립트가 종료되면 임시 파일이 삭제됩니다.

다시 실행하면 현재 디렉터리의 파일에서 줄 번호를 읽고 ...-last이전과 비슷한 방식으로 해당 줄 번호부터 끝까지 로그 파일의 내용을 처리합니다.

이 스크립트 실행 사이에 로그 파일에 아무 것도 출력되지 않는 경우. 로그 파일의 마지막 줄이 표시됩니다.

실행하세요:

$ bash script.sh /var/log/system.log
[lots of output]

$ ls system*
system.log-last

$ cat system.log-last
14758

$ bash script.sh /var/log/system.log
[a few lines of output,
 with the first line being the same as the last of the previous run]

$ cat system.log-last
14768

관련 정보