-1

I have below log file and I want to print names of only those users who had succeeded to login on third attempt only.

cat login.log
user1:failed
user2:failed
user3:success
user1:failed
user2:failed
user4:success
user5:failed
user2:success
user3:failed
user6:success
user1:success
user3:success
user4:success
user4:success
user5:failed
user5:failed
user1:success
user2:failed

expected output is,

user1
user2
  • 6
    what have you tried so far ? – Archemar Jun 12 at 5:24
  • I tried to sort them (cat login.log | awk -F'[:]' '{print $1, $2}' | sort -k1) but not able to put conditions. – Swapnil Dhule Jun 12 at 5:54
  • If you are voting down to any question, you should justify that. Provide your answer and prove that it was indeed an easy question. I will happily accept down vote. – Swapnil Dhule Jun 12 at 5:57
  • Can user names contain :s? Are there any other rules for what chars a user name can/can't contain? – Ed Morton Jun 12 at 12:07
3

try

awk -F: '/failed/ { f[$1]++;} /success/ && f[$1]==2 { print ; f[$1]=0 ; }'

where

  • -F: use : as separator
  • /failed/ { f[$1]++;} count failed login for user
  • /success/ && f[$1]==2 { print $1; f[$1]=0 ; } print result upon condition.

as per comment, in case of special name (line break for readability)

awk -F: '$2 == "failed" { f[$1]++;} 
         $2 == "success" && f[$1]==2 { print ; f[$1]=0 ; }'
  • 1
    and Ididn't downvote by the way. – Archemar Jun 12 at 6:03
  • Thanks buddy! This answer is helpful, however it is not giving exact output. Expected output is, user1 user2 This solution is giving, user2:success user1:success I am working on it. If possible share the specific solution. – Swapnil Dhule Jun 12 at 6:12
  • 1
    @muru you spoil it, that was left as an exercice ... – Archemar Jun 12 at 6:13
  • Thanks to all my mentors! @muru, I already seen that. But I promise, I will find out alternative solution to this and post it soon. Thanks @Archemar! – Swapnil Dhule Jun 12 at 6:17
  • 1
    @EdMorton corrected. – Archemar Jun 12 at 12:35
0

Simple bash-only solution: iterate over the lines, incrementing a counter for each failure, and for each succes checking the value of that counter and if it matches the desired value, generate some output. Bonus sort -u on the end to only output users that match, not every occurance. Possible enhancement would be to reset the counter to 0 on success - but you should be able to work out how to do that yourself.

$ unset FAILURES  # In case you've already tried inthis shell
$ declare -A FAILURES
$ while IFS=: read USERNAME STATUS ; do [ "$STATUS" == "failed" ] && (( FAILURES[$USERNAME] += 1)); [ "$STATUS" == "success" -a "0${FAILURES[$USERNAME]}" -eq 2 ] && echo $USERNAME because status is $STATUS and failures is ${FAILURES[$USERNAME]}; done < login.log | sort -u
user1 because status is success and failures is 2
user2 because status is success and failures is 2
$
0

I would keep track of who has logged in, so we don't match this edge case:

joe:success
joe:failed
joe:failed
joe:success
awk -F: '
    $2 == "failed" {fail[$1]++} 
    $2 == "success" && !loggedin[$1] {
        if (fail[$1] == 2) print $1
        loggedin[$1] = 1
    }
' login.log

Unless you are interested in anyone who logs in after 2 consecutive failures, regardless of any previous logins. In that case you want:

awk -F: '
    $2 == "failed" {fail[$1]++} 
    $2 == "success" {
        if (fail[$1] == 2) print $1
        fail[$1] = 0
    }
' login.log

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.