contar duplicados en una secuencia ordenada usando herramientas de línea de comando

82

Tengo un comando (cmd1) que hace greps a través de un archivo de registro para filtrar un conjunto de números. Los números están en orden aleatorio, así que utilizo sort -gr para obtener una lista de números ordenados al revés. Puede haber duplicados dentro de esta lista ordenada. Necesito encontrar el recuento de cada número único en esa lista.

Por ejemplo, si la salida de cmd1 es:

100 
100 
100 
99 
99 
26 
25 
24 
24

Necesito otro comando al que pueda canalizar la salida anterior, de modo que obtengo:

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

Respuestas:

94

qué tal si;

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

El resultado es :

100 3
99  2
26  1
25  1
24  2
Stephen Paul Lesniewski
fuente
1
Ejecuté esto y produjo una declaración de impresión adicional de $ 1, $ 2 al final:100 3 99 2 26 1 25 1 24 2 2 24
Mittenchops
3
Lo siguiente agrega una nueva línea entre los resultados y elimina la línea adicional al final: 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 -1así obtienes:100 3 99 2 26 1 25 1 24 2
Woody
Nota sobre la sintaxis, puede terminar una línea con una barra vertical en lugar de usar una barra invertida.
wjandrea
53

uniq -c funciona para GNU uniq 8.23 ​​al menos, y hace exactamente lo que quiere (asumiendo una entrada ordenada).

Ibrahim
fuente
2
en caso de que la entrada no esté ordenada, simplemente agregue el sortcomando:sort file_name | uniq -c
Mikhail Geyer
Increíble. ¡Funciona también en Mac OS X! Probado en Mojave 10.14.6.
bappak
10

si el orden no es importante

# 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
fuente
+1 por hacer esto con 3 tuberías menos. Sería increíble si pudieras explicar cómo funciona esto porque me confundió. ;-) Gracias.
SaxDaddy
9

Ordene numéricamente los números al revés, luego cuente los duplicados, luego intercambie las palabras izquierda y derecha. Alinear en columnas.

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
fuente
2

En Bash, podemos usar una matriz asociativa para contar instancias de cada valor de entrada. Suponiendo que tenemos el comando $cmd1, por ejemplo

#!/bin/bash

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

Luego, podemos contar valores en la variable de matriz ausando el ++operador matemático en las entradas de matriz relevantes:

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

Podemos imprimir los valores resultantes:

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

Si el orden de salida es importante, es posible que necesitemos un externo sortde las claves:

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