Risposte:
Il seguente dovrebbe funzionare:
$ sed 's/\(.\)/\1\n/g' text.txt | sort | uniq -c
Innanzitutto, inseriamo una nuova riga dopo ogni personaggio, posizionando ciascun personaggio sulla propria riga. Quindi lo ordiniamo. Quindi usiamo il comando uniq per rimuovere i duplicati, prefissando ogni riga con il numero di occorrenze di quel carattere.
Per ordinare l'elenco per frequenza, reindirizza tutto sort -nr
.
sed
farlo, ma la soluzione Python di Jacob Vlijm ha funzionato bene per me.
La soluzione di Steven è buona, semplice. Non è così performante per file molto grandi (file che non si adattano comodamente a circa la metà della RAM) a causa del passaggio di ordinamento. Ecco una versione awk. E 'anche un po' più complicato, perché cerca di fare la cosa giusta per un paio di caratteri speciali (a capo, '
, \
, :
).
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/:/'
Ecco una soluzione Perl sullo stesso principio. Perl ha il vantaggio di poter ordinare internamente. Inoltre, questo non conterà correttamente una nuova riga se il file non termina con un carattere di nuova riga.
perl -ne '
++$c{$_} foreach split //;
END { printf "'\''%s'\'': %d\n", /[\\'\'']/ ? "\\$_" : /./ ? $_ : "\\n", $c{$_}
foreach (sort {$c{$b} <=> $c{$a}} keys %c) }'
Una versione lenta ma relativamente favorevole alla memoria, usando ruby. Circa una dozzina di MB di RAM, indipendentemente dalle dimensioni dell'input.
# 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