두 타임 스탬프간에 로그를 추출하는 방법


25

두 타임 스탬프 사이의 모든 로그를 추출하고 싶습니다. 일부 라인에는 타임 스탬프가 없을 수도 있지만 해당 라인도 원합니다. 요컨대, 두 개의 타임 스탬프에 해당하는 모든 라인을 원합니다. 내 로그 구조는 다음과 같습니다.

[2014-04-07 23:59:58] CheckForCallAction [ERROR] Exception caught in +CheckForCallAction :: null
--Checking user--
Post
[2014-04-08 00:00:03] MobileAppRequestFilter [DEBUG] Action requested checkforcall

2014-04-07 23:00와 사이의 모든 것을 추출하고 싶다고 가정 해보십시오 2014-04-08 02:00.

시작 타임 스탬프 또는 종료 타임 스탬프가 로그에 없을 수 있지만이 두 타임 스탬프 사이의 모든 줄을 원합니다.



이 작업을 한 번만 또는 프로그래밍 방식으로 여러 번 수행해야합니까?
Bratchley

내가 묻는 이유 는 리터럴 값을 아는 경우 두 개의 상황에 맞는 grep을 시작하는 것입니다 (하나는 시작 구분 기호 다음에 모든 것을 가져오고 다른 하나는 끝 구분 기호에서 인쇄를 중지 합니다) 할 수 있기 때문 입니다. 날짜 / 시간이 변경 될 수있는 경우 tou는 date -d명령을 통해 사용자 입력을 제공하고 이를 사용하여 검색 패턴을 구성하여이를 즉시 생성 할 수 있습니다 .
Bratchley

@Ramesh, 참조 된 질문이 너무 광범위합니다.
maxschlepzig

@JoelDavis : 프로그래밍 방식으로하고 싶습니다. 그래서 매번 원하는 타임 스탬프를 입력하여 내 / tmp 위치에있는 타임 스탬프 사이의 로그를 추출해야합니다.
Amit

답변:


19

awk이것을 위해 사용할 수 있습니다 :

$ awk -F'[]]|[[]' \
  '$0 ~ /^\[/ && $2 >= "2014-04-07 23:00" { p=1 }
   $0 ~ /^\[/ && $2 >= "2014-04-08 02:00" { p=0 }
                                        p { print $0 }' log

어디에:

  • -F정규식을 사용하여 문자 []필드 구분 기호를 지정합니다.
  • $0 완전한 라인을 참조
  • $2 날짜 필드를 참조
  • p 실제 인쇄를 보호하는 부울 변수로 사용됩니다.
  • $0 ~ /regex/ 정규식이 일치하면 true $0
  • >=문자열을 사전 식으로 비교하는 데 사용됩니다 (예 :와 동일 strcmp())

변형

위의 명령 줄은 오른쪽 열림 시간 간격 일치를 구현 합니다. 닫힌 간격 의미를 얻으려면 올바른 날짜를 늘리십시오. 예 :

$ awk -F'[]]|[[]' \
  '$0 ~ /^\[/ && $2 >= "2014-04-07 23:00"    { p=1 }
   $0 ~ /^\[/ && $2 >= "2014-04-08 02:00:01" { p=0 }
                                           p { print $0 }' log

다른 형식으로 타임 스탬프를 일치 시키려면 $0 ~ /^\[/하위 표현식 을 수정해야합니다 . 인쇄 켜짐 / 꺼짐 논리에서 타임 스탬프가없는 행을 무시하는 데 사용되었습니다.

예를 들어 중괄호 YYYY-MM-DD HH24:MI:SS없이 타임 스탬프 형식의 경우 다음과 같이 []명령을 수정할 수 있습니다.

$ awk \
  '$0 ~ /^[0-9]{4}-[0-9]{2}-[0-9]{2} [0-2][0-9]:[0-5][0-9]:[0-5][0-9]/
      {
        if ($1" "$2 >= "2014-04-07 23:00")     p=1;
        if ($1" "$2 >= "2014-04-08 02:00:01")  p=0;
      }
    p { print $0 }' log

(필드 구분 기호도 변경됨-기본값은 공백 / 비 공백으로 변경됨)


스크립트 공유에 대한 감사하지만 종료 타임 스탬프를 확인하지 못했습니다. 확인하시기 바랍니다. 또한 2014-04-07 23:59:58과 같은 로그가 있으면 무엇을 알려주십시오. 나는 중괄호없이 의미
아 미트

@Amit, 답을 업데이트
maxschlepzig

나는 이것이 문자열 문제라고 생각하지는 않지만 ( 내 대답 참조 ) 모든 테스트를 반복하지 않으면 서 훨씬 더 읽기 쉽고 약간 더 빠를 수있다. $1 ~ /^[0-9]{4}-[0-9]{2}-[0-9]{2}/ && $2 ~/[0-2][0-9]:[0-5][0-9]:[0-5][0-9]/ { Time = $1" "$2; if (Time >= "2014-04-07 23:00" ) { p=1 } if (Time >= "2014-04-08 02:00:01" ) { p=0 } } p

안녕 맥스, 하나 더 작은 의심 .. 내가 Apr-07-2014 10:51:17 같은 것을 가지고 있다면. 그런 다음 어떤 변경을해야합니까 .. code$ 0 ~ / ^ [az | AZ] {4}-[0-9] {2}-[0-9] {4} [0-2] [0-9 ] : [0-5] [0-9] : [0-5] [0-9] / && $ 1 ""$ 2> = "Apr-07-2014 11:00"{p = 1} $ 0 ~ / ^ [az | AZ] {4}-[0-9] {2}-[0-9] {4} [0-2] [0-9] : [0-5] [0-9] : [0 -5] [0-9] / && $ 1 ""$ 2> = "Apr-07-2014 12:00:01"{p = 0} code작동하지 않음
Amit

@awk_FTW는 정규식이 명시 적으로 공유되도록 코드를 변경했습니다.
maxschlepzig 2018

12

https://github.com/mdom/dategrepdategrep 에서 확인 하십시오

기술:

dategrep은 명명 된 입력 파일에서 날짜 범위와 일치하는 행을 검색하여 stdout에 인쇄합니다.

dategrep이 검색 가능한 파일에서 작동하는 경우 바이너리 검색을 수행하여 첫 번째 및 마지막 줄을 찾아 매우 효율적으로 인쇄 할 수 있습니다. 파일 이름 인수 중 하나가 하이픈 인 경우 dategrep을 stdin에서 읽을 수도 있지만이 경우 느린 모든 줄을 구문 분석해야합니다.

사용 예 :

dategrep --start "12:00" --end "12:15" --format "%b %d %H:%M:%S" syslog
dategrep --end "12:15" --format "%b %d %H:%M:%S" syslog
dategrep --last-minutes 5 --format "%b %d %H:%M:%S" syslog
dategrep --last-minutes 5 --format rsyslog syslog
cat syslog | dategrep --end "12:15" -

이 제한으로 인해 정확한 질문에 적합하지 않을 수 있습니다.

현재 dategrep은 구문 분석 할 수없는 줄을 찾으면 죽을 것입니다. 향후 버전에서는이를 구성 할 수 있습니다.


나는 단지 며칠 전에이 명령에 대해 onethingwell.org/post/81991115668/dategrep의 의례로 배웠 습니다.
cpugeniusmv

3

awk비표준 도구의 대안 또는 비표준 도구는 grep상황에 맞는 grep에 GNU를 사용하는 것입니다. GNU grep에서는 양의 일치 후 인쇄 할 -A행 수와 이전 행을 인쇄 할 행 수를 지정할 수 있습니다. -B예를 들면 다음 과 같습니다.

[davisja5@xxxxxxlp01 ~]$ cat test.txt
Ignore this line, please.
This one too while you're at it...
[2014-04-07 23:59:58] CheckForCallAction [ERROR] Exception caught in +CheckForCallAction :: null
--Checking user--
Post
[2014-04-08 00:00:03] MobileAppRequestFilter [DEBUG] Action requested checkforcall
we don't
want these lines.


[davisja5@xxxxxxlp01 ~]$ egrep "^\[2014-04-07 23:59:58\]" test.txt -A 10000 | egrep "^\[2014-04-08 00:00:03\]" -B 10000
[2014-04-07 23:59:58] CheckForCallAction [ERROR] Exception caught in +CheckForCallAction :: null
--Checking user--
Post
[2014-04-08 00:00:03] MobileAppRequestFilter [DEBUG] Action requested checkforcall

위의 내용은 기본적으로 grep원하는 패턴과 일치하는 줄을 따르는 10,000 줄을 인쇄하여 출력을 원하는 곳에서 시작하고 끝까지 (희망스럽게) 끝까지 가도록 egrep합니다. 파이프 라인은 끝 구분 기호가있는 행과 그 앞에 10,000 행만 인쇄하도록 지시합니다. 이 두 가지의 최종 결과는 당신이 원하는 곳에서 시작하고 멈추라 고 말한 곳에서지나 가지 않습니다.

10,000은 내가 생각 해낸 숫자이므로 출력이 너무 길다고 생각되면 자유롭게 백만으로 변경하십시오.


시작 및 끝 범위에 대한 로그 항목이 없으면 어떻게 작동합니까? OP가 14:00에서 15:00 사이의 모든 것을 원하지만 14:00에 대한 로그 항목이 없다면?

sed리터럴 일치를 검색하는 것뿐만 아니라 단어에 대해서도 설명합니다. dategrep아마도 주어진 타임 스탬프에 대해 "퍼지"할 수 있어야하기 때문에 주어진 모든 것 중 가장 정확한 답일 것입니다. 그러나 대답처럼, 나는 그것을 대안으로 언급했습니다. 즉, 로그가 절단을 보증하기에 충분한 출력을 생성 할 수있을 정도로 활성화 된 경우 주어진 시간 동안 어떤 종류의 항목이있을 수 있습니다.
Bratchley

0

sed 사용 :

#!/bin/bash

E_BADARGS=23

if [ $# -ne "3" ]
then
  echo "Usage: `basename $0` \"<start_date>\" \"<end_date>\" file"
  echo "NOTE:Make sure to put dates in between double quotes"
  exit $E_BADARGS
fi 

isDatePresent(){
        #check if given date exists in file.
        local date=$1
        local file=$2
        grep -q "$date" "$file"
        return $?

}

convertToEpoch(){
    #converts to epoch time
    local _date=$1
    local epoch_date=`date --date="$_date" +%s`
    echo $epoch_date
}

convertFromEpoch(){
    #converts to date/time format from epoch
    local epoch_date=$1
    local _date=`date  --date="@$epoch_date" +"%F %T"`
    echo $_date

}

getDates(){
        # collects all dates at beginning of lines in a file, converts them to epoch and returns a sequence of numbers
        local file="$1"
        local state="$2"
        local i=0
        local date_array=( )
        if [[ "$state" -eq "S" ]];then
            datelist=`cat "$file" | sed -r -e "s/^\[([^\[]+)\].*/\1/" | egrep  "^[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}"`
        elif [[ "$state" -eq "E" ]];then
            datelist=`tac "$file" | sed -r -e "s/^\[([^\[]+)\].*/\1/" | egrep  "^[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}"`

        else
            echo "Something went wrong while getting dates..." 1>&2
            exit 500
        fi

        while read _date
            do
                epoch_date=`convertToEpoch "$_date"`
                date_array[$i]=$epoch_date
                #echo "$_date" "$epoch_date" 1>&2

            (( i++ ))
            done<<<"$datelist"
        echo ${date_array[@]}   


}

findneighbours(){
    # search next best date if date is not in the file using recursivity
    IFS="$old_IFS"
    local elt=$1
    shift
    local state="$1"
    shift
    local -a array=( "$@" ) 

    index_pivot=`expr ${#array[@]} / 2`
    echo "#array="${#array[@]} ";array="${array[@]} ";index_pivot="$index_pivot 1>&2
    if [ "$index_pivot" -eq 1 -a ${#array[@]} -eq 2 ];then

        if [ "$state" == "E" ];then
            echo ${array[0]}
        elif [ "$state" == "S" ];then
            echo ${array[(( ${#array[@]} - 1 ))]} 
        else
            echo "State" $state "undefined" 1>&2
            exit 100
        fi

    else
        echo "elt with index_pivot="$index_pivot":"${array[$index_pivot]} 1>&2
        if [ $elt -lt ${array[$index_pivot]} ];then
            echo "elt is smaller than pivot" 1>&2
            array=( ${array[@]:0:(($index_pivot + 1)) } )
        else
            echo "elt is bigger than pivot" 1>&2
            array=( ${array[@]:$index_pivot:(( ${#array[@]} - 1 ))} ) 
        fi
        findneighbours "$elt" "$state" "${array[@]}"
    fi
}



findFirstDate(){
    local file="$1"
    echo "Looking for first date in file" 1>&2
    while read line
        do 
            echo "$line" | egrep -q "^\[[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}\]" &>/dev/null
            if [ "$?" -eq "0" ]
            then
                #echo "line=" "$line" 1>&2
                firstdate=`echo "$line" | sed -r -e "s/^\[([^\[]+)\].*/\1/"`
                echo "$firstdate"
                break
            else
                echo $? 1>&2
            fi
        done< <( cat "$file" )



}

findLastDate(){
    local file="$1"
    echo "Looking for last date in file" 1>&2
    while read line
        do 
            echo "$line" | egrep -q "^\[[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}\]" &>/dev/null
            if [ "$?" -eq "0" ]
            then
                #echo "line=" "$line" 1>&2
                lastdate=`echo "$line" | sed -r -e "s/^\[([^\[]+)\].*/\1/"`
                echo "$lastdate"
                break
            else
                echo $? 1>&2
            fi
        done< <( tac "$file" )


}

findBestDate(){

        IFS="$old_IFS"
        local initdate="$1"
        local file="$2"
        local state="$3"
        local first_elts="$4"
        local last_elts="$5"
        local date_array=( )
        local initdate_epoch=`convertToEpoch "$initdate"`   

        if [[ $initdate_epoch -lt $first_elt ]];then
            echo `convertFromEpoch "$first_elt"`
        elif [[ $initdate_epoch -gt $last_elt ]];then
            echo `convertFromEpoch "$last_elt"` 

        else
            date_array=( `getDates "$file" "$state"` )
            echo "date_array="${date_array[@]} 1>&2
            #first_elt=${date_array[0]}
            #last_elt=${date_array[(( ${#date_array[@]} - 1 ))]}

            echo `convertFromEpoch $(findneighbours "$initdate_epoch" "$state" "${date_array[@]}")`

        fi

}


main(){
    init_date_start="$1"
    init_date_end="$2"
    filename="$3"
    echo "problem start.." 1>&2
    date_array=( "$init_date_start","$init_date_end"  )
    flag_array=( 0 0 )
    i=0
    #echo "$IFS" | cat -vte
    old_IFS="$IFS"
    #changing separator to avoid whitespace issue in date/time format
    IFS=,
    for _date in ${date_array[@]}
    do
        #IFS="$old_IFS"
        #echo "$IFS" | cat -vte
        if isDatePresent "$_date" "$filename";then
            if [ "$i" -eq 0 ];then 
                echo "Starting date exists" 1>&2
                #echo "date_start=""$_date" 1>&2
                date_start="$_date"
            else
                echo "Ending date exists" 1>&2
                #echo "date_end=""$_date" 1>&2
                date_end="$_date"
            fi

        else
            if [ "$i" -eq 0 ];then 
                echo "start date $_date not found" 1>&2
            else
                echo "end date $_date not found" 1>&2
            fi
            flag_array[$i]=1
        fi
        #IFS=,
        (( i++ ))
    done

    IFS="$old_IFS"
    if [ ${flag_array[0]} -eq 1 -o ${flag_array[1]} -eq 1 ];then

        first_elt=`convertToEpoch "$(findFirstDate "$filename")"`
        last_elt=`convertToEpoch "$(findLastDate "$filename")"`
        border_dates_array=( "$first_elt","$last_elt" )

        #echo "first_elt=" $first_elt "last_elt=" $last_elt 1>&2
        i=0
        IFS=,
        for _date in ${date_array[@]}
        do
            if [ $i -eq 0 -a ${flag_array[$i]} -eq 1 ];then
                date_start=`findBestDate "$_date" "$filename" "S" "${border_dates_array[@]}"`
            elif [ $i -eq 1 -a ${flag_array[$i]} -eq 1 ];then
                date_end=`findBestDate "$_date" "$filename" "E" "${border_dates_array[@]}"`
            fi

            (( i++ ))
        done
    fi


    sed -r -n "/^\[${date_start}\]/,/^\[${date_end}\]/p" "$filename"

}


main "$1" "$2" "$3"

이것을 파일로 복사하십시오. 디버깅 정보를 보지 않으려면 디버깅이 stderr로 전송되므로 "2> / dev / null"을 추가하십시오.


1
타임 스탬프가없는 로그 파일은 표시되지 않습니다.
Amit

@ 아미, 예, 시도해 보셨습니까?
UnX

@rMistero, 22:30에 로그 항목이 없으면 범위가 종료되지 않기 때문에 작동하지 않습니다. OP에서 언급했듯이 시작 및 중지 시간이 로그에 없을 수 있습니다. 정규식이 작동하도록 조정할 수는 있지만 해상도가 느슨해 져서 적시에 범위가 종료 될 것이라는 보장 없습니다 .

@awk_FTW 이것은 예입니다 .Amit에서 제공 한 타임 스탬프를 사용하지 않았습니다. 다시 정규식을 사용할 수 있습니다. 명시 적으로 제공되거나 타임 스탬프 정규식과 일치하지 않으면 타임 스탬프가 존재하지 않으면 작동하지 않는다고 생각합니다. 곧 개선하겠습니다.
UnX

"OP에서 언급했듯이 시작 및 중지 시간이 로그에 없을 수 있습니다." 아니요, OP를 다시 읽으십시오. OP는 이들이 존재하지만 중간 회선이 반드시 타임 스탬프로 시작되는 것은 아니라고 말합니다. 중지 시간이 존재하지 않을 수도 있다고 말하는 것은 의미가 없습니다. 어떻게 지금 말할 수 있는 정지에 종료 마커가 보장되어 있지 않은 경우 도구를? 처리를 중지 할 위치를 알려주는 도구는 없습니다.
Bratchley
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.