Eindeutig durch zwei Spalten mit zwei Bedingungen

Eindeutig durch zwei Spalten mit zwei Bedingungen

ich habe eine Tabelle mit Spalten. In der ersten Spalte steht die Zeit, wann sich der Benutzer angemeldet hat, in der zweiten Spalte steht der Name des Benutzers.

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

Was soll ich also tun? Ich sollte eine eindeutige Operation mit diesen beiden Spalten durchführen. Und wenn die Zeit der Benutzeranmeldung und der Benutzername gleich sind, sollte ich sagen, dass sich der Benutzer mehr als dreimal angemeldet hat. Ich habe ein kurzes Skript geschrieben:

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

Bitte überprüfen Sie, ob dieses Skript Ihrer Meinung nach korrekt ist. Denn nach der Ausgabe meines Skripts im Echo erhalte ich Folgendes:

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

Aber ich möchte eine Ausgabe wie diese:

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

Und das ist alles. Wo habe ich einen Fehler? Bitte helfen Sie.

Antwort1

Dies können Sie ganz einfach tun mitawk

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

Dieses Programm durchsucht die root.log-Datei, erstellt ein assoziatives Array (auch Hash genannt) mit der Anzahl aller Benutzer und druckt dann diejenigen aus, die größer als eins sind.

Antwort2

Das einzige Problem ist also, dass die gleiche Ausgabe mehrfach gedruckt wird? Warum nicht einfach durch Uniq leiten? In eine andere temporäre Datei kopieren und dann Uniq darauf ausführen?

Wenn das nicht das ist, wonach Sie fragen, habe ich einige Anmerkungen:

  • Das Arbeiten mit zeilengetrennten Daten in Bash/SH ist normalerweise mehr Aufwand als es wert ist. Wenn die Lösung nicht offensichtlich ist, greifen Sie zu einer Skriptsprache, in der Sie nicht ständig mit IFS herumfummeln müssen. (Wenn Sie nicht wissen, was die IFS-Variable ist, empfehle ich Ihnen wirklich, Bash/SH für zeilengetrennte Daten zu meiden.)
  • da Sie bereits awk verwenden, können Sie das Ganze bestimmt als awk-Skript erledigen.
  • Da die Zeilen, die Sie betreffen, identisch sind, können Sie Folgendes tun sort logfile | uniq -c.
  • Sie sortieren Ihre Datei nicht vor uniq, daher funktioniert uniq nicht, wenn die identischen Zeilen nicht nebeneinander stehen. Z. B. wenn Bob und Joe sich gleichzeitig anmelden und ihre Protokolleinträge sich abwechseln.
  • es gibt immer grep -c
  • Informieren Sie sich über den Sortierbefehl, insbesondere -d, -n, -k und -t

AKTUALISIEREN

Bitten Sie um Ratschläge zum Shell-Scripting oder suchen Sie nach einer praktischen Antwort auf die Frage „Wie finde ich heraus, wer aktuell in drei oder mehr Sitzungen angemeldet ist?“

Ratschläge zum Skripting:

  • Ich bin ziemlich sicher, $sdass es die gesamte Zeichenfolge 4 21erdsf123sdfsdf <newline> 4 abcasbbabadabeinschließlich einer neuen Zeile enthält. Ich kann nicht genau herausfinden, warum.
  • Warum machst du das awk '{print $5}'? Ich habe versucht, deine Beispieldaten zu kopieren und auszuführen, awk '{print $5}'aber ich habe nur eine Reihe von Zeilenumbrüchen und sonst nichts bekommen.
  • Haben Sie sich den Inhalt angesehen $temp_fileund $temp_file2sichergestellt, dass er Ihren Erwartungen entspricht?
  • Das tail -n 20sagt mir, dass Sie nur „aktuelle“ Einträge wollen und es Ihnen egal ist, wie aktuell sie sind. Stimmt das?
  • Die cat /dev/null > $fileZeilen sind überflüssig, nehmen Sie sie einfach heraus.
  • Ersetzen Sie cat $logfiledurchsort $logfile
  • Schleifen einrücken

Im Grunde wird dieses Skript nicht das tun, was Sie wollen, und ich kann nicht sagen, wie es funktionieren soll, also kann ich Ihnen keinen spezifischeren Rat geben. Tut mir leid.

praktisch

  • benutze @greg-tarsas awk-Skript (tut mir leid, Greg, herzlichen Glückwunsch, ich weiß nicht, ob ich einen Benutzer mit einem Leerzeichen in seinem Namen verlinken soll)
  • Sprechen Sie über aktuelle Anmeldungen bei einer Unix-Box? Haben Sie den whoBefehl ausprobiert? EG who | awk '{ print $1}' | sort | uniq -c | sort -d -roder den lastBefehl?
  • Suchen Sie nach der Antwort auf Ihre allgemeine Frage (wie finde ich heraus, wer sich zu oft angemeldet hat/hat) statt nach der spezifischeren Frage, die die Lösung blockiert, die Sie bereits zu implementieren versuchen (Uniq durch zwei Spalten mit zwei Bedingungen). Wenn Sie mehr daran interessiert sind, Ihr Shell-Scripting zu üben, stellen Sie Ihre Frage so, dass dies zum Ausdruck kommt.

verwandte Informationen