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


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

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).


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

+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

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
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.