Angenommen, Sie haben eine Datei mit IP-Adressen, eine Adresse in jeder Zeile:
10.0.10.1
10.0.10.1
10.0.10.3
10.0.10.2
10.0.10.1
Sie benötigen ein Shell-Skript, das für jede IP-Adresse zählt, wie oft sie in der Datei angezeigt wird. Für die vorherige Eingabe benötigen Sie die folgende Ausgabe:
10.0.10.1 3
10.0.10.2 1
10.0.10.3 1
Eine Möglichkeit, dies zu tun, ist:
cat ip_addresses |uniq |while read ip
do
echo -n $ip" "
grep -c $ip ip_addresses
done
Es ist jedoch weit davon entfernt, effizient zu sein.
Wie würden Sie dieses Problem mit bash effizienter lösen?
(Eine Sache zum Hinzufügen: Ich weiß, dass es von Perl oder Awk gelöst werden kann. Ich bin an einer besseren Lösung in Bash interessiert, nicht in diesen Sprachen.)
ZUSÄTZLICHE INFORMATION:
Angenommen, die Quelldatei ist 5 GB groß und der Computer, auf dem der Algorithmus ausgeführt wird, verfügt über 4 GB. Sortieren ist also keine effiziente Lösung, und die Datei wird auch nicht mehr als einmal gelesen.
Ich mochte die Hashtable-ähnliche Lösung - kann jemand Verbesserungen an dieser Lösung vornehmen?
ZUSÄTZLICHE INFO # 2:
Einige Leute fragten, warum ich mir die Mühe machen würde, es in Bash zu machen, wenn es in Perl viel einfacher ist. Der Grund ist, dass auf der Maschine, die ich machen musste, diese Perl für mich nicht verfügbar war. Es war eine speziell angefertigte Linux-Maschine ohne die meisten Tools, die ich gewohnt bin. Und ich denke, es war ein interessantes Problem.
Also bitte, beschuldigen Sie die Frage nicht, ignorieren Sie sie einfach, wenn Sie sie nicht mögen. :-)
Antworten:
Dadurch wird zuerst die Anzahl gedruckt, aber ansonsten sollte es genau das sein, was Sie wollen.
quelle
sort ip_addresses | uniq -c | sort -nr
sort ip_addresses | uniq -c | sort -nr | awk '{ print $2, $1 }'
um die IP-Adresse in der ersten Spalte zu erhalten und in der zweiten zu zählen.sort -nr -k1,1
Die schnelle und schmutzige Methode ist wie folgt:
cat ip_addresses | sort -n | uniq -c
Wenn Sie die Werte in bash verwenden müssen, können Sie den gesamten Befehl einer bash-Variablen zuweisen und dann die Ergebnisse durchlaufen.
PS
Wenn der Befehl sort weggelassen wird, erhalten Sie nicht die richtigen Ergebnisse, da uniq nur aufeinanderfolgende identische Zeilen betrachtet.
quelle
Verwenden Sie das folgende Beispiel, um mehrere Felder basierend auf einer Gruppe vorhandener Felder zusammenzufassen: (Ersetzen Sie die $ 1, $ 2, $ 3, $ 4 gemäß Ihren Anforderungen.)
quelle
sort
unduniq
am einfachsten zu zählen sind, aber nicht helfen, wenn Sie Feldwerte berechnen / summieren müssen. Die Array-Syntax von awk ist sehr leistungsfähig und der Schlüssel zur Gruppierung. Vielen Dank!print
Funktion von awk 64-Bit-Ganzzahlen auf 32 Bit zu verkleinern scheint. Für int-Werte über 2 ^ 31 möchten Sie möglicherweiseprintf
das%.0f
Format anstelle vonprint
dort verwendenarr[$1,$2]+=$3+$4
mit zBarr[$1,$2]=(arr[$1,$2] $3 "," $4). I needed this to provide a grouped-by-package list of files (two columns only) and used:
arr [$ 1] = (arr [$ 1] $ 2) `mit Erfolg.Die kanonische Lösung ist die von einem anderen Befragten erwähnte:
Es ist kürzer und prägnanter als das, was in Perl oder awk geschrieben werden kann.
Sie schreiben, dass Sie sort nicht verwenden möchten, da die Daten größer sind als der Hauptspeicher des Computers. Unterschätzen Sie nicht die Implementierungsqualität des Unix-Sortierbefehls. Sort wurde verwendet, um sehr große Datenmengen (denken Sie an die ursprünglichen Rechnungsdaten von AT & T) auf Computern mit 128 KB (das sind 131.072 Byte) Speicher (PDP-11) zu verarbeiten. Wenn beim Sortieren mehr Daten als ein voreingestellter Grenzwert festgestellt werden (häufig nahe an der Größe des Hauptspeichers des Geräts abgestimmt), werden die im Hauptspeicher gelesenen Daten sortiert und in eine temporäre Datei geschrieben. Anschließend wird die Aktion mit den nächsten Datenblöcken wiederholt. Schließlich führt es eine Zusammenführungssortierung für diese Zwischendateien durch. Auf diese Weise kann die Sortierung Daten verarbeiten, die um ein Vielfaches größer sind als der Hauptspeicher des Geräts.
quelle
Dieser Befehl würde Ihnen die gewünschte Ausgabe geben
quelle
Es scheint, dass Sie entweder eine große Menge Code verwenden müssen, um Hashes in Bash zu simulieren, um ein lineares Verhalten zu erhalten, oder sich an die
quadratischensuperlinearen Versionen halten müssen.Unter diesen Versionen ist die Lösung von saua die beste (und einfachste):
Ich habe http://unix.derkeiler.com/Newsgroups/comp.unix.shell/2005-11/0118.html gefunden . Aber es ist höllisch hässlich ...
quelle
Lösung (gruppieren nach wie MySQL)
Ergebnis
quelle
Sie können wahrscheinlich das Dateisystem selbst als Hash-Tabelle verwenden. Pseudocode wie folgt:
Am Ende müssen Sie nur alle Dateien durchlaufen und die Dateinamen und -nummern darin drucken. Anstatt eine Zählung beizubehalten, können Sie alternativ jedes Mal ein Leerzeichen oder eine neue Zeile an die Datei anhängen und am Ende nur die Dateigröße in Byte anzeigen.
quelle
Ich denke, ein awk assoziatives Array ist auch in diesem Fall praktisch
Eine Gruppe per Post hier
quelle
Die meisten anderen Lösungen zählen Duplikate. Wenn Sie Schlüsselwertpaare wirklich gruppieren müssen, versuchen Sie Folgendes:
Hier sind meine Beispieldaten:
Dadurch werden die Schlüsselwertpaare gedruckt, die in der md5-Prüfsumme gruppiert sind.
quelle
Rein Bash (keine Gabel!)
Es gibt einen Weg, a BashFunktion . Dieser Weg ist sehr schnell, da es keine Gabel gibt! ...
... während viele IP-Adressen klein bleiben !
Hinweis: IP-Adressen werden in vorzeichenlose 32-Bit-Ganzzahlwerte konvertiert, die als Index für das Array verwendet werden . Dies verwendet einfache Bash-Arrays , keine assoziativen Arrays (was teurer ist)!
Auf meinem Host ist dies viel schneller als die Verwendung von Gabeln, bis zu ca. 1'000 Adressen, aber es dauert ungefähr 1 Sekunde, wenn ich versuche, 10'000 Adressen zu sortieren und zu zählen .
quelle
Ich hätte es so gemacht:
aber uniq könnte für Sie arbeiten.
quelle
Ich verstehe, dass Sie in Bash nach etwas suchen, aber falls jemand anderes in Python nach etwas sucht, sollten Sie Folgendes in Betracht ziehen:
Da die Werte im Set standardmäßig eindeutig sind und Python in diesem Bereich ziemlich gut ist, können Sie hier möglicherweise etwas gewinnen. Ich habe den Code nicht getestet, daher ist er möglicherweise fehlerhaft, aber dies bringt Sie möglicherweise dorthin. Und wenn Sie Vorkommen zählen möchten, ist die Verwendung eines Diktats anstelle eines Satzes einfach zu implementieren.
Edit: Ich bin ein mieser Leser, also habe ich falsch geantwortet. Hier ist ein Ausschnitt mit einem Diktat, das Vorkommen zählt.
Das Wörterbuch mydict enthält jetzt eine Liste eindeutiger IP-Adressen als Schlüssel und die Häufigkeit, mit der sie als Werte aufgetreten sind.
quelle
itertools.groupby()
diesorted()
genau das tut, was OP verlangt.Die Sortierung kann weggelassen werden, wenn die Reihenfolge nicht von Bedeutung ist
oder
wenn die Quellliste eine Variable ist
quelle