Isso funciona, a menos que eu tenha entendido sua pergunta de maneira errada:
$ grep -v -f <(grep " ok$" aa.txt |cut -d' ' -f1) aa.txt
user2
user5
user7
user8
user9
Na realidade, usamos grep para todos os nomes marcados como ok, e usamos esses nomes como um padrão a ser excluído do mesmo arquivo para obter logins "não ok".
Isso é baseado no fato de que, como o user1 tinha no final um login bem-sucedido (mesmo depois de três tentativas), user1 não é considerado uma falha, portanto, todas as tentativas do usuário1 são excluídas.
grep -v: excluir padrão
grep -f: carrega padrões do arquivo, aqui uma substituição de processo que contém os logins bem-sucedidos.
PS1: o arquivo aa.txt é um dos meus arquivos locais nos quais colei seus dados.
Atualização:
Usar <(grep " ok$" aa.txt |cut ...)
com um espaço antes de ok garantirá que os nomes de usuários que falharam no login, mas incluam "ok" em seus nomes, não serão correspondidos (por exemplo, usuário Bangok)