Jawaban:
Berikut ini harus bekerja:
$ sed 's/\(.\)/\1\n/g' text.txt | sort | uniq -c
Pertama, kami menyisipkan baris baru setelah setiap karakter, menempatkan setiap karakter pada barisnya masing-masing. Lalu kami mengatasinya. Kemudian kami menggunakan perintah uniq untuk menghapus duplikat, mengawali setiap baris dengan jumlah kemunculan karakter itu.
Untuk mengurutkan daftar berdasarkan frekuensi, masukkan semua ini ke dalam sort -nr.
sedmelakukan ini, tetapi solusi Python Jacob Vlijm bekerja dengan baik untuk saya.
Solusi Steven adalah solusi yang bagus dan sederhana. Ini tidak begitu performan untuk file yang sangat besar (file yang tidak pas dengan nyaman di sekitar setengah RAM Anda) karena langkah penyortiran. Ini versi awk. Ini juga sedikit lebih rumit karena mencoba untuk melakukan hal yang benar untuk beberapa karakter khusus (baris baru, ', \, :).
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/:/'
Berikut adalah solusi Perl pada prinsip yang sama. Perl memiliki keuntungan karena dapat memilah secara internal. Juga ini dengan benar tidak akan menghitung baris baru tambahan jika file tidak berakhir dengan karakter baris baru.
perl -ne '
++$c{$_} foreach split //;
END { printf "'\''%s'\'': %d\n", /[\\'\'']/ ? "\\$_" : /./ ? $_ : "\\n", $c{$_}
foreach (sort {$c{$b} <=> $c{$a}} keys %c) }'
Versi lambat tapi relatif ramah memori, menggunakan ruby. Tentang selusin MB RAM, terlepas dari ukuran 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