-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

3 Answers3

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 ; }'
Archemar
  • 31,554
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
$
  • There's nothing simple about that. It'd remove some backslashes, convert others preceding specific chars to different chars, possibly clash with environment variables, do globbing, etc. It'd also be very slow. See https://unix.stackexchange.com/q/169716/133219, https://mywiki.wooledge.org/Quotes and https://stackoverflow.com/questions/673055/correct-bash-and-shell-script-variable-capitalization – Ed Morton Jun 12 '19 at 12:04
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
glenn jackman
  • 85,964