![Eindeutig durch zwei Spalten mit zwei Bedingungen](https://rvso.com/image/697372/Eindeutig%20durch%20zwei%20Spalten%20mit%20zwei%20Bedingungen.png)
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,
$s
dass es die gesamte Zeichenfolge4 21erdsf123sdfsdf <newline> 4 abcasbbabadab
einschließ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_file
und$temp_file2
sichergestellt, dass er Ihren Erwartungen entspricht? - Das
tail -n 20
sagt mir, dass Sie nur „aktuelle“ Einträge wollen und es Ihnen egal ist, wie aktuell sie sind. Stimmt das? - Die
cat /dev/null > $file
Zeilen sind überflüssig, nehmen Sie sie einfach heraus. - Ersetzen Sie
cat $logfile
durchsort $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
who
Befehl ausprobiert? EGwho | awk '{ print $1}' | sort | uniq -c | sort -d -r
oder denlast
Befehl? - 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.