perl -MO=Deparse -lnE "$ar[0]++; $ar[pos]{$1}++ while /(.)/g; END{ foreach $row (1..$#ar){print join qq(\t),$row,map{$_,sprintf('%.2f',$ar[$row]{$_}/$ar[0] )} sort keys %{$ar[$row]}}}" freq.txt BEGIN { $/ = "\n"; $\ = "\n"; } # implicit initialization BEGIN { $^H{'feature_unicode'} = q(1); $^H{'feature_say'} = q(1); $^H{'feature_state'} = q(1); $^H{'feature_switch'} = q(1); } # our program: LINE: while (defined($_ = )) { # reading all files because of perl -n chomp $_; # automatic handling of end of line given by perl -l ++$ar[0]; # el 0 keeps track of line processed ++$ar[pos $_]{$1} while /(.)/g; # /(.)/g return all char setting $1 to # the char and making pos returning it's position # so with ++ we augment occurences of char given by $1 # found at position given by pos sub END { foreach $row (1 .. $#ar) { # now we process rows of the array starting # from 1, because position coincide with array index print join("\t", # joining all following with a tab $row, # the row is equal to the position in the string map({ # then foreach key of the hash (the el. $row of @a) $_, # the sorted key sprintf('%.2f', $ar[$row]{$_} / $ar[0]); # it's value divided # by linecount, formatted } sort(keys %{$ar[$row];}))); } } ; } -e syntax OK