특정 텍스트를 사용하여 현재 날짜보다 이후의 특정 시간에 대한 로그를 필터링하려고 합니다. 현재 날짜가 포함된 텍스트에 대한 로그를 성공적으로 필터링했습니다. 이것은 명령입니다:
grep "$(date +"%d/%b/%Y")" test.log | grep -i "failed login"
샘플 로그는 다음과 같습니다.
[04/Dec/2019 02:05:13 -0800] access WARNING 10.126.49.92 -anon- - "POST /hue/accounts/login HTTP/1.1"-- Failed login for user: testuser
[04/Dec/2019 02:05:15 -0800] access WARNING 10.126.49.92 -anon- - "POST /hue/accounts/login HTTP/1.1"-- Failed login for user: testuser
[04/Dec/2019 02:04:59 -0800] access INFO 10.126.49.92 ahmed.rao - "POST /notebook/api/check_status HTTP/1.1" returned in 759ms
[04/Dec/2019 02:05:00 -0800] base INFO Selected cluster 0e83a448-26c9-459b-a0f2-3478ecb119af {u'interface': u'impala', u'namespace': u'0e83a448-26c9-459b-a0f2-3478ecb119af', u'type': u'direct', u'id': u'0e83a448-26c9-459b-a0f2-3478ecb119af', u'name': u'0e83a448-26c9-459b-a0f2-3478ecb119af'} interface hiveserver2
[04/Dec/2019 03:05:00 -0800] access INFO 10.126.49.92 ahmed.rao - "POST /notebook/api/close_statement HTTP/1.1" returned in 1345ms
[04/Dec/2019 03:05:00 -0800] base INFO Selected cluster 0e83a448-26c9-459b-a0f2-3478ecb119af {u'interface': u'impala', u'namespace': u'0e83a448-26c9-459b-a0f2-3478ecb119af', u'type': u'direct', u'id': u'0e83a448-26c9-459b-a0f2-3478ecb119af', u'name': u'0e83a448-26c9-459b-a0f2-3478ecb119af'} interface hiveserver2
[04/Dec/2019 03:05:18 -0800] access WARNING 10.126.49.92 -anon- - "POST /hue/accounts/login HTTP/1.1"-- Failed login for user: testuser
그런데 특정 시간보다 큰 조건을 적용하는 방법을 모르겠습니다.
답변1
ts
from 을 사용하면 moreutils
이러한 타임스탬프를 보다 유용한 형식으로 쉽게 변환할 수 있습니다.
ts -r %FT%T%z < file.log |
awk '$0 > "[2019-12-04T02:50" && tolower($0) ~ /failed login/'
귀하의 입력 (및 timezone America/Los_Angeles
)을 고려하면 다음과 같습니다.
[2019-12-04T03:05:18-0800] access WARNING 10.126.49.92 -anon- - "POST /hue/accounts/login HTTP/1.1"-- Failed login for user: testuser
ts
해당 타임스탬프를 구문 분석 하고 -r
지정된 %FT%T%z
strftime
형식(시간대로)으로 변환합니다.
형식은 어휘 및 시간순으로 동일하게 정렬되므로 지정된 날짜보다 이후의 항목을 찾으 YYYY-MM-DDTHH:MM:SS
려면 문자열 비교만 필요합니다 . 여전히 일을 할 수 있습니다 . 여기서는 대소문자를 구분하지 않는 표준 일치 방법이 사용됩니다 . GNU를 사용하면 다음을 수행할 수도 있습니다.awk
awk
grep -i
tolower()
awk
gawk -v IGNORECASE=1 '$0 > "[2019-12-04T02:50" && /failed login/'
없는 경우 's를 사용하여 moreutils
구문 분석을 수행할 수 있습니다('s를 사용하는 Perl 스크립트이지만 's와는 반대로 의 핵심 모듈 중 하나가 아니므로 시스템에 설치되지 않을 수 있음).perl
Time::Piece
ts
Date::Parse
Time::Piece
perl
CUT=2019-12-04T02:50:00-0800 perl -MTime::Piece -F'[][]' -ale '
BEGIN{$cut = Time::Piece->strptime($ENV{CUT}, "%FT%T%z")}
print if /failed login/i &&
Time::Piece->strptime($F[1], "%d/%b/%Y %T %z") >= $cut' < file.log
1 DST를 적용하는 시간대에서 겨울/여름 시계 변경 시간을 무시하면
답변2
누군가가 유용하다고 생각할 경우를 대비해 남겨두겠습니다. 하지만 그냥 사용하세요.이 답변대신에. 더 간단하고 효율적입니다.
Perl 메소드는 다음과 같습니다.
$ perl -lne 'if(/^\[([^]]+)/){$d=$1; chomp($dateThreshold=`date -d "04 Dec 2019" +%s`); $d=~s|/| |g; chomp($d=`date -d "$d" +%s`); print if $d >= $dateThreshold;} ' test.log
[04/Dec/2019 02:05:13 -0800] access WARNING 10.126.49.92 -anon- - "POST /hue/accounts/login HTTP/1.1"-- Failed login for user: testuser
[04/Dec/2019 02:05:15 -0800] access WARNING 10.126.49.92 -anon- - "POST /hue/accounts/login HTTP/1.1"-- Failed login for user: testuser
[04/Dec/2019 02:04:59 -0800] access INFO 10.126.49.92 ahmed.rao - "POST /notebook/api/check_status HTTP/1.1" returned in 759ms
[04/Dec/2019 02:05:00 -0800] base INFO Selected cluster 0e83a448-26c9-459b-a0f2-3478ecb119af {u'interface': u'impala', u'namespace': u'0e83a448-26c9-459b-a0f2-3478ecb119af', u'type': u'direct', u'id': u'0e83a448-26c9-459b-a0f2-3478ecb119af', u'name': u'0e83a448-26c9-459b-a0f2-3478ecb119af'} interface hiveserver2
[04/Dec/2019 03:05:00 -0800] access INFO 10.126.49.92 ahmed.rao - "POST /notebook/api/close_statement HTTP/1.1" returned in 1345ms
[04/Dec/2019 03:05:00 -0800] base INFO Selected cluster 0e83a448-26c9-459b-a0f2-3478ecb119af {u'interface': u'impala', u'namespace': u'0e83a448-26c9-459b-a0f2-3478ecb119af', u'type': u'direct', u'id': u'0e83a448-26c9-459b-a0f2-3478ecb119af', u'name': u'0e83a448-26c9-459b-a0f2-3478ecb119af'} interface hiveserver2
[04/Dec/2019 03:05:18 -0800] access WARNING 10.126.49.92 -anon- - "POST /hue/accounts/login HTTP/1.1"-- Failed login for user: testuser
그리고 더 명확하게 말하자면:
perl -lne 'if(/^\[([^]]+)/){ ## skip lines that do not match
## Save the date of the current line as $d
$d=$1;
## Replace all slashes with pipes so the 'date' command
## can read this as a date.
$d=~s|/| |g;
## Now, translate $d into seconds since the epoch
chomp($d=`date -d "$d" +%s`);
## Set the threshold date in seconds since the epoch.
chomp($dateThreshold=`date -d "04 Dec 2019" +%s`);
## Print this line if its date is greater than or equal to the threshold
print if $d >= $dateThreshold;
} ' test.log
BEGIN
마지막으로 스크립트가 시작될 때 한 번만 실행되도록 임계값 설정 단계를 블록으로 이동하여 효율성을 향상시킬 수 있습니다 .
perl -lne 'BEGIN{chomp($dateThreshold=`date -d "04 Dec 2019" +%s`); } if(/^\[([^]]+)/){$d=$1; $d=~s|/| |g; chomp($d=`date -d "$d" +%s`); print if $d >= $dateThreshold;} ' test.log
답변3
awk
GNU 명령을 호출하는 GNU 를 사용한 또 다른 답변은 다음과 같습니다 date
.
awk
(우리가 부르는) 프로그램은 다음 find_after_timestamp.awk
과 같습니다:
BEGIN{
gsub("/"," ",start_datetime)
extcmd=sprintf("date -d \"%s\" +\"%%Y %%m %%d %%H %%M %%S\"",start_datetime)
extcmd | getline startstring
close(extcmd)
start_ts=mktime(startstring)
print "Lines will be matched starting with timestamp",start_ts
printf("Will look for: \"%s\"\n",searchpat)
}
{
if (match($0,/^\[([[:print:]]*)\][[:print:]]*$/,line_datetime)==0) next
gsub("/"," ",line_datetime[1])
extcmd=sprintf("date -d \"%s\" +\"%%Y %%m %%d %%H %%M %%S\"",line_datetime[1])
extcmd | getline line_dtstring
close(extcmd)
line_ts=mktime(line_dtstring)
if (line_ts > start_ts && $0 ~ searchpat) print
}
당신은 그것을 부를 것입니다
awk -v start_datetime="04/Dec/2019 02:05:21 -0800" -v searchpat="[Ff]ailed login" -f find_after_timestamp.awk test.log
여기서 변수는 start_datetime
검색 범위의 시작이 됩니다. 즉, 날짜/시간이 이 시점과 같거나 이후인 모든 항목이 고려됩니다. 값은 start_datetime
로그 파일과 동일한 형식이어야 하지만 그 외에는 임의적이며 파일에 실제로 존재하는 값일 필요는 없습니다. 이 변수에는 searchpat
찾고 있는 패턴이 포함됩니다.
설명하다
DD/MONTH/YYYY HH:MM:SS TIMEZONE
이 구조 는 날짜 부분date
의 . 를 공백으로 대체 하여 ("비표준"이 아닌) 날짜/시간 사양을 GNU가 이해할 수 있는 것으로 변환하는 것을 중심으로 진행됩니다 ./
gsub
그런 다음 셸에서 문자열을 실행 하고 결과를 문자열 변수로 읽어
date
(설정 단계, 파일 구문 분석 단계에서) 외부 명령을 호출합니다. 이제 내장 함수가 ist를 구문 분석할 수 있도록 형식이 지정됩니다.extcmd
startstring
line_dtstring
awk
mktime
이
mktime
명령은 사람이 읽을 수 있는 날짜/시간 사양을 산술 비교를 사용하여 비교할 수 있는 순수 숫자 UNIX 시간으로 변환합니다.단계 에서는
BEGIN
시작 날짜 사양을 변환하기 위해 수행되고 본문에서는 현재 행과 연결된 타임스탬프를 변환하기 위해 수행됩니다. 타임스탬프가 없는 행은 무시됩니다(if (match(...)==0) next
).현재 행에 참조 시작 타임스탬프보다 큰(= 이후) 타임스탬프가 있고
searchpat
해당 행에서 발견되면 해당 행이 인쇄됩니다.
awk
프로그램에서 외부 프로그램에 의존해야 한다는 것이 약간 눈살을 찌푸리게 한다는 것을 알고 있지만 이는 거의 모든 설치에서 사용할 수 있는 기본 도구를 사용하여 수행할 수 있습니다.
답변4
sed를 사용하세요:
sed -n "/$(date +'%d\/%b\/%Y')/,/*/p" test.log | grep -i "failed login"
- 일치(날짜) 이후의 모든 내용을 인쇄합니다.
참고: 현재 날짜는 로그 파일에서 확인할 수 있어야 합니다.