SELECT COUNT(*), campo FROM cosa GROUP BY campo
se logra en shell scripts con
sort | uniq -c
(siempre que consideremos que 'campo' es toda la línea)
El comando uniq toma el input y lo repite en el output, removiendo duplicados. La opción -c indica la cantidad de repeticiones. Como no ordena, tenemos que hacerlo previamente.
Si hiciéramos simplemente uniq -c, nos podrían quedar varios bloques para el mismo valor.
Pero si nuestro input tiene grandes bloques de valores repetidos, un sort de todos contra todos los valores gastaría tiempo en ordenar internamente esos bloques, cuando uniq -c los reduciría rápidamente.
Hoy me soprendí una vez más de la potencia de awk. Mi idea fue hacer un uniq -c inicial, sin sort, y resolver la duplicación de bloques con awk, así:
uniq -c | awk '{h[$2]+=$1} END {for (i in h) print h[i],i}'
O si queremos emular EXACTA y coquetamente el resultado del uniq:
uniq -c | awk '{h[$2]+=$1} END {for (i in h) printf "%7d %d\n", h[i],i}'
Explico:
Para cada línea del uniq -c que es de forma:
Metemos en un array asociativo indexado por "valor" la frecuencia (sumando al valor que ya tenemos).
Cuando llegamos al final (END), mostramos el array.
Hice cuentas con un archivo de 7.9Gb con grandes bloques, y para mi asombro sort no la pasó taaan mal. Sospecho que sort está usando alguna clase de mergeSort para ordenamiento en memoria secundaria.
Comparo los tiempos de hacer un simple uniq -c (que no resuelve nuestro porblema), un sort | uniq -c y mi sugerencia. Asombrosamente, el mío anda más rápido que el uniq -c a solas. Creo que eso está dentro de la tolerancia de la medición, o hubieron factores externos en el server.
uniq.time
real 5m40.97s
user 6m25.65s
sys 0m2.47s
sort.time
real 7m4.77s
user 7m26.90s
sys 0m4.57s
mio.time
real 5m37.56s
user 6m20.91s
sys 0m2.35s