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


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

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


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

+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

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
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.