Zählen von Duplikaten in einer sortierten Reihenfolge mit Befehlszeilentools

82

Ich habe einen Befehl (cmd1), der eine Protokolldatei durchsucht, um eine Reihe von Zahlen herauszufiltern. Die Zahlen sind in zufälliger Reihenfolge, daher verwende ich sort -gr, um eine umgekehrt sortierte Liste von Zahlen zu erhalten. Diese sortierte Liste enthält möglicherweise Duplikate. Ich muss die Anzahl für jede eindeutige Nummer in dieser Liste finden.

Zum Beispiel, wenn die Ausgabe von cmd1 ist:

100 
100 
100 
99 
99 
26 
25 
24 
24

Ich benötige einen anderen Befehl, an den ich die obige Ausgabe weiterleiten kann, damit ich Folgendes erhalte:

100     3
99      2
26      1
25      1
24      2
letronje
quelle
Verwandte: serverfault.com/questions/37020/…
David Cary
verwandt: stackoverflow.com/a/16980265/32453
rogerdpack

Antworten:

94

wie wäre es mit;

$ echo "100 100 100 99 99 26 25 24 24" \
    | tr " " "\n" \
    | sort \
    | uniq -c \
    | sort -k2nr \
    | awk '{printf("%s\t%s\n",$2,$1)}END{print}'

Das Ergebnis ist :

100 3
99  2
26  1
25  1
24  2
Stephen Paul Lesniewski
quelle
1
Ich habe dies ausgeführt und es wurde eine zusätzliche Druckaufstellung von 1 $, 2 $ am Ende erstellt:100 3 99 2 26 1 25 1 24 2 2 24
Mittenchops
3
Das Folgende fügt eine neue Zeile zwischen den Ergebnissen hinzu und entfernt die zusätzliche Zeile am Ende: echo "100 100 100 99 99 26 25 24 24" | tr " " "\n" | sort | uniq -c | sort -k2nr | awk '{printf("%s\t%s\n",$2,$1)}END{print}' | head -n -1so erhalten Sie:100 3 99 2 26 1 25 1 24 2
Woody
Hinweis zur Syntax: Sie können eine Zeile mit einer Pipe beenden, anstatt einen Backslash zu verwenden.
Wjandrea
53

uniq -c funktioniert mindestens für GNU uniq 8.23 ​​und macht genau das, was Sie wollen (unter der Annahme einer sortierten Eingabe).

Ibrahim
quelle
2
Falls die Eingabe nicht sortiert ist, fügen Sie einfach den folgenden sortBefehl hinzu:sort file_name | uniq -c
Mikhail Geyer
Genial. Funktioniert auch unter Mac OS X! Getestet am Mojave 10.14.6.
Bappak
10

wenn die Reihenfolge nicht wichtig ist

# echo "100 100 100 99 99 26 25 24 24" | awk '{for(i=1;i<=NF;i++)a[$i]++}END{for(o in a) printf "%s %s ",o,a[o]}'
26 1 100 3 99 2 24 2 25 1
Ghostdog74
quelle
+1 dafür mit 3 weniger Rohren. Es wäre großartig, wenn Sie näher erläutern könnten, wie dies funktioniert, da es mich verwirrt hat. ;-) Vielen Dank.
SaxDaddy
9

Sortieren Sie die Zahlen numerisch in umgekehrter Reihenfolge, zählen Sie dann die Duplikate und tauschen Sie das linke und das rechte Wort aus. In Spalten ausrichten.

printf '%d\n' 100 99 26 25 100 24 100 24 99 \
   | sort -nr | uniq -c | awk '{printf "%-8s%s\n", $2, $1}'
100     3
99      2
26      1
25      1
24      2
Ericcurtin
quelle
2

In Bash können wir ein assoziatives Array verwenden, um Instanzen jedes Eingabewerts zu zählen. Angenommen, wir haben den Befehl $cmd1, z

#!/bin/bash

cmd1='printf %d\n 100 99 26 25 100 24 100 24 99'

Dann können wir Werte in der Array-Variablen amit dem ++mathematischen Operator für die relevanten Array-Einträge zählen:

while read i
do
    ((++a["$i"]))
done < <($cmd1)

Wir können die resultierenden Werte drucken:

for i in "${!a[@]}"
do
    echo "$i ${a[$i]}"
done

Wenn die Reihenfolge der Ausgabe wichtig ist, benötigen wir möglicherweise eine externe sortTaste:

for i in $(printf '%s\n' "${!a[@]}" | sort -nr)
do
    echo "$i ${a[$i]}"
done
Toby Speight
quelle