Uniq por duas colunas com duas condições

Uniq por duas colunas com duas condições

eu tenho uma tabela com colunas. Na primeira coluna, tenho tempo, quando o usuário efetuou login, na segunda coluna, tenho um nome de usuário.

13:15:39  fxs1cia1qulm1lk  
13:15:39  fxs1cia1qulm1lk  
13:15:39  fxs1cia1qulm1lk  
13:15:42  faaaa2aa11111  
13:15:49  terd1sfsd11fsdf  
13:15:49  terd1sfsd11fsdf  
13:15:49  terd1sfsd11fsdf  
13:15:59  21erdsf123sdfsdf   
13:15:59  21erdsf123sdfsdf   
13:15:59  21erdsf123sdfsdf   
13:15:59  21erdsf123sdfsdf   
13:17:50  abcasbbabadab  
13:17:50  abcasbbabadab  
13:17:50  abcasbbabadab  
13:17:50  abcasbbabadab   
13:19:19  fxs1ce1iulmla   
13:19:19  fxs1ce1iulmla  
13:19:19  fxs1ce1iulmla   
13:20:42  faaa2a0a1111

Então, o que devo fazer. Eu deveria fazer uma operação única com essas duas colunas, e se o tempo de login do usuário e o nome do usuário forem iguais, devo dizer que esse usuário efetuou login mais de 3 vezes. Eu escrevi um pequeno roteiro:

log_file=/root/log
temp_file=/root/temp
temp_file2=/root/temp2

cat /dev/null > $temp_file
cat /dev/null > $temp_file2
cat /dev/null > $result_file

cat $log_file | awk '{print $1}' | tail -n 20 > $temp_file
cat $log_file | awk '{print $5}' | tail -n 20 > $temp_file2

for i in `uniq -c $temp_file | awk '{print $1}'`; do
for y in `uniq -c $temp_file2 | awk '{print $2}'`; do
if [ $i -gt 3 ] && [ $y -gt 3 ]; then
s=`uniq -c $temp_file2 | awk '$1 == '$i`
echo "The user $s has logged more than 3 times"
fi
done
done

Por favor, verifique, como você acha, este script está correto? Porque, após a saída do meu script em echo, eu tenho isso:

The user       4 21erdsf123sdfsdf   
      4 abcasbbabadab  has logged more than 3 times
The user       4 21erdsf123sdfsdf   
      4 abcasbbabadab  has logged more than 3 times
The user       4 21erdsf123sdfsdf   
      4 abcasbbabadab  has logged more than 3 times
The user       4 21erdsf123sdfsdf   
      4 abcasbbabadab  has logged more than 3 times

Mas eu quero ter uma saída como esta:

The user       4 21erdsf123sdfsdf has logged more than 3 times
The user       4 abcasbbabadab  has logged more than 3 times

E isso é tudo. Onde eu cometi um erro? Por favor ajude.

Responder1

Você pode fazer isso de uma maneira muito direta comawk

awk '{ users[$2]++ }
END {
     for (user in users)
       if (users[user] > 1)
         printf "%s logged in %d times\n", user, users[user]
    }' < /root.log

Este programa verifica o root.log criando um array associativo (também conhecido como hash) com contagens de cada usuário e, em seguida, imprime aqueles que são maiores que um.

Responder2

Então, o único problema é que ele imprime a mesma saída várias vezes? Por que não apenas passar pelo uniq? Despejar em outro arquivo temporário e executar o uniq nele?

Se não é isso que você está perguntando, tenho algumas observações:

  • trabalhar com dados separados por linha no bash/sh geralmente é mais problemático do que vale a pena. A menos que a solução seja óbvia, procure uma linguagem de script onde você não precise mexer no IFS o tempo todo. (Se você não sabe o que é o IFS var, então eu realmente recomendo ficar longe do bash/sh para dados separados por linha.)
  • como você já está usando o awk, aposto que você poderia fazer tudo como um script awk.
  • Como as linhas com as quais você está preocupado são idênticas, você pode fazer isso sort logfile | uniq -c.
  • Você não está classificando seu arquivo antes do uniq, então o uniq não funcionará se as linhas idênticas não estiverem próximas umas das outras. Por exemplo, se Bob e Joe fizerem login ao mesmo tempo e suas entradas de log forem alternadas.
  • sempre há grep -c
  • leia sobre o comando sort, especialmente -d, -n, -k e -t

ATUALIZAR

Você está pedindo conselhos sobre scripts de shell ou está procurando uma resposta prática para a questão de como faço para descobrir quem está conectado em 3 ou mais sessões?

conselhos de script:

  • Tenho certeza que $scontém a string inteira, 4 21erdsf123sdfsdf <newline> 4 abcasbbabadabincluindo uma nova linha. Não consigo entender por quê.
  • Por que você faz awk '{print $5}'? Tentei copiar seus dados de exemplo e executá-los awk '{print $5}', mas obtive um monte de novas linhas e nada mais.
  • Você examinou o conteúdo de $temp_filee $temp_file2para ter certeza de que é o que você espera?
  • Isso tail -n 20me diz que você quer apenas entradas 'recentes' e não se importa com o quão recentes. Isso é verdade?
  • As cat /dev/null > $filelinhas são redundantes, basta retirá-las.
  • Substitua o cat $logfileporsort $logfile
  • Recue seus loops

Basicamente, esse script não fará o que você deseja e não sei dizer como você pretendia que funcionasse, portanto não posso dar conselhos mais específicos. Desculpe.

prático

  • use o script awk de @ greg-tarsa ​​('desculpas para' e, Greg me heartie, eu não sei o 'link' para um usuário com um espaço em 'seu nome)
  • você está falando sobre logins atuais em uma caixa unix? Você já tentou o whocomando? EG who | awk '{ print $1}' | sort | uniq -c | sort -d -rou o lastcomando?
  • procure a resposta para sua pergunta geral (como faço para descobrir quem está logado muitas vezes) em vez da pergunta mais específica que está bloqueando a solução que você já está tentando implementar (Uniq por duas colunas com duas condições) . Se você estiver mais interessado em praticar seu script de shell, faça sua pergunta de uma forma que diga isso.

informação relacionada