27

I am trying to find out the frequency of appearance of every letter in the english alphabet in an input file. How can I do this in a bash script?

SkypeMeSM
  • 2,876
  • 7
  • 40
  • 59

5 Answers5

28

My solution using grep, sort and uniq.

grep -o . file | sort | uniq -c

Ignore case:

grep -o . file | sort -f | uniq -ic
dogbane
  • 242,394
  • 72
  • 372
  • 395
24

Just one awk command

awk -vFS="" '{for(i=1;i<=NF;i++)w[$i]++}END{for(i in w) print i,w[i]}' file

if you want case insensitive, add tolower()

awk -vFS="" '{for(i=1;i<=NF;i++)w[tolower($i)]++}END{for(i in w) print i,w[i]}' file

and if you want only characters,

awk -vFS="" '{for(i=1;i<=NF;i++){ if($i~/[a-zA-Z]/) { w[tolower($i)]++} } }END{for(i in w) print i,w[i]}' file

and if you want only digits, change /[a-zA-Z]/ to /[0-9]/

if you do not want to show unicode, do export LC_ALL=C

ghostdog74
  • 286,686
  • 52
  • 238
  • 332
7

A solution with sed, sort and uniq:

sed 's/\(.\)/\1\n/g' file | sort | uniq -c

This counts all characters, not only letters. You can filter out with:

sed 's/\(.\)/\1\n/g' file | grep '[A-Za-z]' | sort | uniq -c

If you want to consider uppercase and lowercase as same, just add a translation:

sed 's/\(.\)/\1\n/g' file | tr '[:upper:]' '[:lower:]' | grep '[a-z]' | sort | uniq -c
mouviciel
  • 62,742
  • 10
  • 106
  • 135
  • Thanks. This considers uppercase and lowercase characters as separate. How can I calculate the frequencies where we consider A and a as same? – SkypeMeSM Oct 19 '10 at 09:42
  • Yes this works great as well. I am wondering how can I calculate the probabilities i.e. frequency/total sum. We will need to pipe the output again to sed again but I cannot figure out the regex involved? – SkypeMeSM Oct 19 '10 at 11:22
  • You can add some `wc`, `cut`, `dc`, `tee` and other commands but it would be more juggling with plates than a maintainable work. I think that adding more features would be easier with a perl script. – mouviciel Oct 19 '10 at 11:43
  • Thank you very very much for your help. Cheers. – SkypeMeSM Oct 19 '10 at 12:45
4

Here is a suggestion:

while read -n 1 c
do
    echo "$c"
done < "$INPUT_FILE" | grep '[[:alpha:]]' | sort | uniq -c | sort -nr
Benoit
  • 70,220
  • 21
  • 189
  • 223
0

Similar to mouviciel's answer above, but more generic for Bourne and Korn shells used on BSD systems, when you don't have GNU sed, which supports \n in a replacement, you can backslash escape a newline:

sed -e's/./&\
/g' file | sort | uniq -c | sort -nr

or to avoid the visual split on the screen, insert a literal newline by type CTRL+V CTRL+J

sed -e's/./&\^J/g' file | sort | uniq -c | sort -nr
Anthony C Howe
  • 551
  • 4
  • 6