bash (grep/sed/etc)를 사용하여 2 개의 타임 스탬프 사이의 로그 파일 섹션을 잡을 수 있습니까?

StackOverflow https://stackoverflow.com/questions/827930

문제

메일 로그 세트가 있습니다 : mail.log mail.log.0 mail.log.1.gz mail.log.2.gz

이러한 각 파일에는 다음과 같은 타임 스탬프로 시작하는 시간순으로 정렬 된 줄이 포함되어 있습니다.

5 월 3 일 13:21:12 ...

특정 날짜/시간 후에 그리고 다른 날짜/시간 전에 모든 로그 항목을 쉽게 잡을 수 있습니까? Bash 사용 (및 관련 명령 줄 도구) 모든 한 줄을 비교하지 않고? 내 전후 날짜는 로그 파일의 항목과 정확히 일치하지 않을 수 있습니다.

시작 타임 스탬프보다 첫 번째 줄의 오프셋과 마지막 줄의 오프셋을 끝 타임 스탬프보다 낮게 결정하고 해당 섹션을 어떻게 든 잘라 내야한다고 생각합니다.

도움이 되었습니까?

해결책 2

여기에서 어떻게하는 방법에 대한 기본 아이디어 :

  1. 검사하십시오 파일의 Datestamp 관련이 있는지 확인합니다
  2. 그 경우 ~할 수 있었다 필요한 경우 압축을 풀고 검사하십시오 첫 번째와 마지막 줄 파일의 시작 또는 완료 시간이 포함되어 있는지 확인합니다.
  3. 그렇다면 a 재귀 기능 파일의 1 차 또는 후반에 시작 시간이 포함되어 있는지 확인합니다. 재귀 함수를 사용하면 약 20 개의 비교로 백만 라인 로그 파일로 날짜를 찾을 수 있다고 생각합니다.
  4. 첫 번째 항목의 오프셋에서 마지막 항목의 오프셋으로 순서대로 로그 파일을 Echo (더 이상 비교 없음)

내가 모르는 것은 : 파일의 n 번째 줄을 가장 잘 읽는 방법 (사용하는 것이 얼마나 효율적입니까? 꼬리 n+** n| 머리 1 **?)

도움이 있습니까?

다른 팁

Min/Max 날짜를 "Epoch 이후 몇 초"로 변환합니다.

MIN=`date --date="$1" +%s`
MAX=`date --date="$2" +%s`

첫 번째를 변환하십시오 n 각 로그 라인의 단어는 동일하게

L_DATE=`echo $LINE | awk '{print $1 $2 ... $n}'`
L_DATE=`date --date="$L_DATE" +%s`

도달 할 때까지 라인을 비교하고 버리십시오 MIN,

if (( $MIN > $L_DATE )) ; then continue ; fi

도달 할 때까지 라인을 비교하고 인쇄하십시오 MAX,

if (( $L_DATE <= $MAX )) ; then echo $LINE ; fi

초과하면 종료하십시오 MAX.

if (( $L_DATE > $MAX )) ; then exit 0 ; fi

전체 스크립트 minmaxlog.sh 이렇게 보인다.

#!/usr/bin/env bash

MIN=`date --date="$1" +%s`
MAX=`date --date="$2" +%s`

while true ; do
    read LINE
    if [ "$LINE" = "" ] ; then break ; fi

    L_DATE=`echo $LINE | awk '{print $1 " " $2 " " $3 " " $4}'`
    L_DATE=`date --date="$L_DATE" +%s`

    if (( $MIN > $L_DATE  )) ; then continue ; fi
    if (( $L_DATE <= $MAX )) ; then echo $LINE ; fi
    if (( $L_DATE >  $MAX )) ; then break ; fi
done

나는이 파일에 그것을 실행했다 minmaxlog.input,

May 5 12:23:45 2009 first line
May 6 12:23:45 2009 second line
May 7 12:23:45 2009 third line
May 9 12:23:45 2009 fourth line
June 1 12:23:45 2009 fifth line
June 3 12:23:45 2009 sixth line

이와 같이,

./minmaxlog.sh "May 6" "May 8" < minmaxlog.input

원하는 범위의 모든 단일 줄을 살펴 봐야합니다 (원하는 범위에 있는지 알려주기 위해). 그래서 파일의 모든 줄을 의미하는 것은 아닙니다. 최소한 최소한 파일의 모든 라인을 범위 외부의 첫 번째 줄을 포함시켜야합니다 (선이 날짜/시간 순서라고 가정합니다).

이것은 상당히 간단한 패턴입니다.

state = preprint
for every line in file:
    if line.date >= startdate:
        state = print
    if line.date > enddate:
        exit for loop
    if state == print:
        print line

당신은 이것을 awk, perl, python, 심지어 COBOL에도 쓸 수 있지만 논리는 항상 동일합니다.

먼저 라인 번호를 찾은 다음 (GREP와 함께) GREP도 모든 라인을보아야하기 때문에 라인 범위를 맹목적으로 인쇄하는 데 도움이되지 않습니다 (모두 그들 중에서도 첫 번째 범위 외부에 이르기까지 두 배, 하나는 첫 번째 줄에이고 마지막 줄을위한 것).

이것이 당신이 자주 할 일이라면, 당신은 '파일이 안정화 될 때'한 번 '한 번에서'할 때마다 '에서 노력을 바꾸는 것을 고려할 수 있습니다. 예를 들어 로그 파일 줄을 날짜/시간에 따라 인덱싱 된 데이터베이스에로드하는 것입니다.

설정하는 데 시간이 걸리지 만 쿼리가 훨씬 빨라지게됩니다. 반드시 데이터베이스를 옹호하는 것은 아닙니다. 로그 파일을 시간별 로그로 나누어 동일한 효과를 얻을 수 있습니다.

2009/
  01/
    01/
      0000.log
      0100.log
      : :
      2300.log
    02/
    : :

그런 다음 주어진 시간 동안, 당신은 어디서부터 시작하고 멈출 곳을 정확히 알 수 있습니다. 범위 2009/01/01-15:22 ~을 통해 2009/01/05-09:07 결과를 초래할 것입니다.

  • 파일의 일부 (마지막 비트) 2009/01/01/1500.txt.
  • 모든 파일 2009/01/01/1[6-9]*.txt.
  • 모든 파일 2009/01/01/2*.txt.
  • 모든 파일 2009/01/0[2-4]/*.txt.
  • 모든 파일 2009/01/05/0[0-8]*.txt.
  • 파일의 일부 (첫 번째 비트) 2009/01/05/0900.txt.

물론, 나는 매번 수동으로 시도하지 않고 그 줄을 반환하기 위해 스크립트를 작성했습니다.

아마 당신은 이것을 시도 할 수 있습니다 :

sed -n "/BEGIN_DATE/,/END_DATE/p" logfile

배쉬 환경에서는 가능할 수 있지만 현악기 및 날짜 작업을위한 더 많은 내장을 지원하는 도구를 활용해야합니다. 예를 들어 루비는 날짜 형식을 구문 분석 할 수있는 능력이있는 것 같습니다. 그런 다음 쉽게 비교할 수있는 유닉스 타임 스탬프 (에포크 이후 초를 나타내는 양의 정수)로 변환 할 수 있습니다.

irb> require 'time'
# => true

irb> Time.parse("May 3 13:21:12").to_i
# => 1241371272  

그런 다음 루비 스크립트를 쉽게 쓸 수 있습니다.

  • 시작 및 종료 날짜를 제공하십시오. 이 Unix 타임 스탬프 번호로 변환하십시오.
  • 로그 파일을 한 줄씩 스캔하여 날짜를 Unix 타임 스탬프로 변환하고 시작 및 종료 날짜 범위에 있는지 확인하십시오.

참고 : UNIX 타임 스탬프 정수로 변환하는 것은 먼저 정수를 비교하는 것이 매우 쉽고 효율적이기 때문에 좋습니다.

"모든 줄을 비교하지 않고"언급했습니다. 로그 파일의 위치에서 "추측"하기가 어려울 것입니다. 로그 파일에서 항목이 너무 오래되기 시작하거나 그 사이의 모든 값을 확인하지 않고 너무 새로워지기가 어려울 것입니다. 그러나 실제로 단조롭게 증가하는 추세가있는 경우, 다음 항목이 너무 새롭게 (또는 데이터의 레이아웃에 따라) 검색을 중지 할 수 있다는 것을 알고 있기 때문에 라인을 구문 분석을 중지 해야하는시기를 즉시 알 수 있습니다. 그럼에도 불구하고 원하는 범위에서 첫 번째 줄을 찾는 데 문제가 있습니다.


방금 편집 한 것을 발견했습니다. 여기에 내가 말할 내용은 다음과 같습니다.

당신이있는 경우 진짜 시작 및 종료 항목을 효율적으로 찾는 것에 대해 걱정하면 각각의 이진 검색을 수행 할 수 있습니다. 또는 BASH 도구를 사용하는 과도한 것처럼 보이거나 너무 어려워 보인다면 라인의 5% 만 읽는 휴리스틱 (20 분마다 1 명)을 읽고 정확한 답변에 신속하게 가까이 다가 가서 원하는 경우이를 정제 할 수 있습니다. 이것들은 성능 향상을위한 몇 가지 제안 일뿐입니다.

나는이 스레드가 오래되었음을 알고 있지만 최근에 내 필요에 대한 한 줄의 솔루션을 찾은 후 우연히 발견했습니다.

awk -v ts_start="2018-11-01" -v ts_end="2018-11-15" -F, '$1>=ts_start && $1<ts_end' myfile

이 경우 내 파일에는 쉼표가 분리 된 값과 첫 번째 필드에 타임 스탬프가있는 레코드가 있습니다. 시작 및 엔드 타임 스탬프에 유효한 타임 스탬프 형식을 사용할 수 있으며 원하는 경우 쉘 변수를 교체 할 수 있습니다.

새 파일에 쓰려면 일반 출력 리디렉션 만 사용하십시오 (> newfile) 위의 끝까지 추가.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top