liczenie duplikatów w posortowanej kolejności za pomocą narzędzi wiersza poleceń

82

Mam polecenie (cmd1), które przegląda plik dziennika, aby odfiltrować zestaw liczb. Liczby są w kolejności losowej, więc używam sort -gr, aby uzyskać odwrotnie posortowaną listę liczb. Na tej posortowanej liście mogą znajdować się duplikaty. Muszę znaleźć liczbę dla każdej unikalnej liczby na tej liście.

Na przykład, jeśli wyjście cmd1 to:

100 
100 
100 
99 
99 
26 
25 
24 
24

Potrzebuję innego polecenia, do którego mogę przesłać powyższe dane wyjściowe, aby uzyskać:

100     3
99      2
26      1
25      1
24      2
letronje
źródło

Odpowiedzi:

94

Co powiesz na;

$ 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}'

Wynik to :

100 3
99  2
26  1
25  1
24  2
Stephen Paul Lesniewski
źródło
1
Uruchomiłem to i otrzymałem dodatkowe wydrukowane zestawienie w wysokości 1 USD, 2 USD na końcu:100 3 99 2 26 1 25 1 24 2 2 24
Mittenchops,
3
Poniższe polecenie dodaje nową linię między wynikami i usuwa dodatkową linię na końcu: 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 -1więc otrzymujesz:100 3 99 2 26 1 25 1 24 2
Woody
Zwróć uwagę na składnię, możesz zakończyć linię pionową kreską zamiast używać odwrotnego ukośnika.
wjandrea
54

uniq -c działa przynajmniej dla GNU uniq 8.23 ​​i robi dokładnie to, co chcesz (zakładając posortowane dane wejściowe).

Ibrahim
źródło
2
w przypadku, gdy dane wejściowe nie są posortowane, po prostu dodaj sortpolecenie:sort file_name | uniq -c
Michaił Geyer
Niesamowite. Działa również na Mac OS X! Testowane na Mojave 10.14.6.
bappak
10

jeśli porządek nie jest ważny

# 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
źródło
+1 za zrobienie tego z 3 rurami mniej. Byłoby wspaniale, gdybyś mógł rozwinąć, jak to działa, bo mnie to zdezorientowało. ;-) Dzięki.
SaxDaddy
9

Liczbowo posortuj liczby w odwrotnej kolejności, policz duplikaty, a następnie zamień lewe i prawe słowa. Wyrównaj do kolumn.

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
źródło
2

W Bash możemy użyć tablicy asocjacyjnej, aby policzyć wystąpienia każdej wartości wejściowej. Zakładając, że posiadamy polecenie $cmd1np

#!/bin/bash

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

Następnie możemy policzyć wartości w zmiennej tablicowej aza pomocą ++operatora matematycznego na odpowiednich wpisach tablicy:

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

Otrzymane wartości możemy wydrukować:

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

Jeśli kolejność danych wyjściowych jest ważna, możemy potrzebować zewnętrznego sortz kluczy:

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