Respuestas:
Lo siguiente debería funcionar:
$ sed 's/\(.\)/\1\n/g' text.txt | sort | uniq -c
Primero, insertamos una nueva línea después de cada carácter, poniendo cada carácter en su propia línea. Luego lo clasificamos. Luego usamos el comando uniq para eliminar los duplicados, prefijando cada línea con el número de ocurrencias de ese carácter.
Para ordenar la lista por frecuencia, canalice todo esto en sort -nr
.
sed
esto, pero la solución Python de Jacob Vlijm funcionó bien para mí.
La solución de Steven es buena y simple. No es tan eficaz para archivos muy grandes (archivos que no caben cómodamente en aproximadamente la mitad de su RAM) debido al paso de clasificación. Aquí hay una versión awk. También es un poco más complicado, ya que trata de hacer lo correcto para algunos caracteres especiales (saltos de línea, '
, \
, :
).
awk '
{for (i=1; i<=length; i++) ++c[substr($0,i,1)]; ++c[RS]}
function chr (x) {return x=="\n" ? "\\n" : x==":" ? "\\072" :
x=="\\" || x=="'\''" ? "\\" x : x}
END {for (x in c) printf "'\''%s'\'': %d\n", chr(x), c[x]}
' | sort -t : -k 2 -r | sed 's/\\072/:/'
Aquí hay una solución de Perl con el mismo principio. Perl tiene la ventaja de poder clasificar internamente. Además, esto no contará correctamente una nueva línea adicional si el archivo no termina en un carácter de nueva línea.
perl -ne '
++$c{$_} foreach split //;
END { printf "'\''%s'\'': %d\n", /[\\'\'']/ ? "\\$_" : /./ ? $_ : "\\n", $c{$_}
foreach (sort {$c{$b} <=> $c{$a}} keys %c) }'
Una versión lenta pero relativamente amigable con la memoria, que usa ruby. Alrededor de una docena de MB de RAM, independientemente del tamaño de entrada.
# count.rb
ARGF.
each_char.
each_with_object({}) {|e,a| a[e] ||= 0; a[e] += 1}.
each {|i| puts i.join("\t")}
ruby count.rb < input.txt
t 20721
d 20628
S 20844
k 20930
h 20783
... etc
sed 's/\(.\)/\1\'$'\n/g' text.txt