awk를 사용하여 동일한 파일의 줄 패턴을 비교하는 방법

awk를 사용하여 동일한 파일의 줄 패턴을 비교하는 방법

우선, 저는 이제 막 배우기 시작했고 awk이 작업을 완료하기 위해 도전하고 싶기 bash때문에 완전한 답변을 찾는 것이 아니라 해결책이 아닌 여기저기서 몇 가지 팁과 이를 수행하는 방법을 찾고 있습니다.

기본적으로 이와 같은 큰 로그 파일을 얻었고 다음과 같이 구성해야 합니다.

  • 사용자가 로그인하고, 비밀번호를 변경하고, 사용자가 동일한 초 내에 로그아웃합니다(3가지 작업이 모두 1초 내에 완료되어야 함).
  • 이러한 작업(로그인, 비밀번호 변경, 로그아웃)은 그 사이에 다른 작업 없이 차례로 발생합니다.

따라서 내 출력은 위의 테스트와 일치하는 사용자의 프로필 이름만 나와야 합니다.

fxsciaqulmlk
erdsfsdfsdf
fxsciaqulmla

여기에 로그 파일의 일부가 있습니다.

Mon, 22 Aug 2016 13:15:39 +0200|178.57.66.225|fxsciaqulmlk| - |user logged in| -
Mon, 22 Aug 2016 13:15:39 +0200|178.57.66.225|fxsciaqulmlk| - |user changed password| -
Mon, 22 Aug 2016 13:15:39 +0200|178.57.66.225|fxsciaqulmlk| - |user logged off| -
Mon, 22 Aug 2016 13:15:42 +0200|178.57.66.225|faaaaaa11111| - |user logged in| -
Mon, 22 Aug 2016 13:15:40 +0200|178.57.66.215|terdsfsdfsdf| - |user logged in| -
Mon, 22 Aug 2016 13:15:49 +0200|178.57.66.215|terdsfsdfsdf| - |user changed password| -
Mon, 22 Aug 2016 13:15:49 +0200|178.57.66.215|terdsfsdfsdf| - |user logged off| -
Mon, 22 Aug 2016 13:15:59 +0200|178.57.66.205|erdsfsdfsdf| - |user logged in| -
Mon, 22 Aug 2016 13:15:59 +0200|178.57.66.205|erdsfsdfsdf| - |user logged in| -
Mon, 22 Aug 2016 13:15:59 +0200|178.57.66.205|erdsfsdfsdf| - |user changed password| -
Mon, 22 Aug 2016 13:15:59 +0200|178.57.66.205|erdsfsdfsdf| - |user logged off| -
Mon, 22 Aug 2016 13:17:50 +0200|178.57.66.205|abcbbabab| - |user logged in| -
Mon, 22 Aug 2016 13:17:50 +0200|178.57.66.205|abcbbabab| - |user changed password| -
Mon, 22 Aug 2016 13:17:50 +0200|178.57.66.205|abcbbabab| - |user changed profile| -
Mon, 22 Aug 2016 13:17:50 +0200|178.57.66.205|abcbbabab| - |user logged off| -
Mon, 22 Aug 2016 13:19:19 +0200|178.56.66.225|fxsciaqulmla| - |user logged in| -
Mon, 22 Aug 2016 13:19:19 +0200|178.56.66.225|fxsciaqulmla| - |user changed password| -
Mon, 22 Aug 2016 13:19:19 +0200|178.56.66.225|fxsciaqulmla| - |user logged off| -
Mon, 22 Aug 2016 13:20:42 +0200|178.57.67.225|faaaa0a11111| - |user logged in| -

이것이 내가 붙어있는 곳입니다.

#!/bin/bash

LIMIT="3"
LOG_FILE="${1}"


if [[ ! -e "${LOG_FILE}" ]]; then
  echo "Cannot open log file: ${LOG_FILE}" >&2
  exit 1
else
  grep 'changed password' -B1 -A1 ${LOG_FILE} \
  | awk '{print $5"\t"$6"\t"$9" "$10}' \
  | awk 'BEGIN{FS="|"; OFS="\t"} {print $1,$3,$4}' \
  | cut -d "    " -f1,3,4,5

....

fi

내 논리는 다음과 같습니다. "로그인" 뒤와 "로그아웃" 앞 줄에 "변경된 비밀번호" 문자열이 있는지 확인하고 싶습니다. 이 두 항목이 일치하면 이러한 작업이 같은 초 내에 완료되었는지 비교하고 싶습니다.

내 논리가 좋은지, awk이 작업을 수행하려면 무엇을 사용해야 하는지 알려주시기 바랍니다. 저도 배우고 싶은데 뭔가 설명해주시면 정말 감사하겠습니다.

답변1

파일에 3줄 창을 유지하고 마지막 패턴이 발견될 때마다 현재 및 마지막 2줄에 대해 테스트할 수 있습니다.

BEGIN {
    FS = "|"
    text[2] = "user logged in"
    text[1] = "user changed password"
    text[0] = "user logged off"
}
    
$5 == text[0] && action[1] == text[1] && action[2] == text[2] &&
$3 == user[1] && $1 == time[1] && $3 == user[2] && $1 == time[2] {
    print $3
}
    
{
    time[2] = time[1]; user[2] = user[1]; action[2] = action[1]
    time[1] = $1; user[1] = $3; action[1] = $5
}

용법:

$ awk -f tst.awk file
fxsciaqulmlk
erdsfsdfsdf
fxsciaqulmla
  • BEGIN그룹은 첫 번째 줄을 구문 분석하기 전에 실행되며 FS필드 구분 기호입니다.

  • 두 번째 그룹은 조건부로 인쇄 사용자와 일치합니다. 스파게티와 비슷하지만 작동합니다. awk첫 번째 오류가 발견되면 각 섹션의 평가가 중지되므로 순서가 중요합니다 . 따라서 먼저 해당 줄에 "로그아웃"이 포함되어 있는지 테스트한 다음 처음 두 줄에 다른 작업이 포함되어 있는지 테스트합니다.

  • 마지막 그룹은 3줄 창을 예약하는 데 사용됩니다. 해시가 있는 변수는 [1]마지막 줄을 의미하고, 해시가 있는 변수는 [2]두 번째에서 마지막 줄을 의미합니다.

  • 참고: 초기화되지 않은 모든 변수는 빈 문자열(또는 숫자 0, 유형이 느슨함)로 처리됩니다. 또한 awk배열은 연관 배열이며 1여기서는 2해시 값입니다.


처음 몇 줄에 대해 더 다르거나 더 많은 테스트를 원하는 경우 뼈대는 다음과 같습니다.

condition_for_last_row {
    for (i=1;i<=2;i++) {
        n = split(prev[i],arr)
        # do comparisons here, arr[1] to arr[n] are
        # the fields of the i-th previous row
    }
}

{
    prev[2] = prev[1]
    prev[1] = $0
}

답변2

awk 대신 Perl을 사용하는 것은 주로 str2time()Date::Parse 모듈의 기능을 용이하게 하기 위한 것입니다:

$ perl -MDate::Parse -F'\|' -lane '
  if    (/user logged in/)        { $event{$F[2]}{login}  = str2time($F[0]) }

  elsif (/user changed password/) { $event{$F[2]}{passwd} = str2time($F[0]) }

  elsif (/user logged off/ &&
         defined($event{$F[2]}{login})  && 
         defined($event{$F[2]}{passwd}) &&
         (str2time($F[0]) - $event{$F[2]}{login} <= 1)) { print $F[2]; delete $event{$F[2]} }

  else { delete $event{$F[2]} }' input.log 
fxsciaqulmlk
erdsfsdfsdf
fxsciaqulmla

이 Perl 원라이너는날짜::분석모듈시간 날짜컬렉션은 날짜 필드를 time_t 값(1970년 1월 1일 자정인 신기원 이후 초)으로 변환합니다.

이 옵션은 perl에게 각 줄을 인쇄하지 않고 입력을 반복하고( s 옵션 -n과 유사 ) 자동으로 각 입력 줄을 배열로 분할하도록 지시합니다 ( and 옵션을 사용하면 perl이 각 줄을 자동으로 분할하는 awk와 유사하게 동작하게 됩니다). ) $1, $2, $3 등의 행을 입력합니다.) 이 옵션은 Perl이 입력과 출력에서 ​​줄 끝 개행을 자동으로 처리하도록 지시합니다.sed-n@F-a-F'\|'-l

스크립트는 로그인하고 비밀번호를 변경하는 사용자와 이러한 이벤트가 이라는 해시(연관 배열)에서 발생하는 시기를 추적합니다 %events. %events는 실제로 Hash-of-Hashes입니다(HoH, 자세한 내용은 Perl Data Structures Cookbook을 참조하세요. 참고자료 참조 man perldsc). 여기서 각 요소(사용자 이름으로 입력)는 또 다른 해시( 또는 로 login입력 passwd, 타임스탬프가 값)입니다.

특정 사용자에 대한 두 개의 이벤트가 확인된 후 동일한 사용자가 로그인 후 1초 이내에 로그아웃된 것을 확인하면 사용자 이름을 인쇄하고 해당 사용자 이름에 대한 이벤트를 삭제합니다.

해당 사용자와 관련된 다른 이벤트가 발견되면 해당 사용자에 대한 현재 이벤트 기록을 모두 삭제합니다.

한 줄 스크립트로 작성되었지만 독립형 스크립트로 쉽게 변환할 수 있습니다.

참고: Bash 및 기타 여러 언어의 배열과 마찬가지로 Perl 배열은 1이 아닌 0에서 시작합니다. 따라서 $F[0]첫 번째 필드(날짜 및 시간)는 $F[2]세 번째 필드(사용자 이름)입니다.

관련 정보