Several years ago, we had the "history meme", in which individuals mine their shell histories to find their ten most executed Unix commands.
What interested me was how the shell one-liner to discover the "top ten" morphed as people got ahold of it -- a glorious game of Geek Chinese Whispers. Each variant is a small puzzle of "Why did they do that?"
The first version I saw was AWK-based:
history \
| awk '{a[$2]++} END{for(i in a){print a[i] " " i}}' \
| sort -rn \
| head
(Note: for zsh, you need something like history -1000 instead of
plain history.)
Aside: AWK was the first Unix-y language with associative arrays (used here); that's where Perl nicked them.
I also saw a neater-printing version of the same thing:
history \
| awk '{a[$2]++} END{for(i in a){printf "%5d\t%s \n",a[i],i}}' \
| sort -rn \
| head
Another version eschewed AWK for true Unix purity:
history \
| tr -s ' ' \
| cut -d ' ' -f 3 \
| sort \
| uniq -c \
| sort -rn \
| head -n 10
(The -n 10 on head is sadly unidiomatic -- that's the default.)
The third variant used just a little AWK to avoid Unix obscurantism:
history \
| awk '{print $2}' \
| sort \
| uniq -c \
| sort -rn \
| head
Colleague Gordon McGregor's version (and it was he who forced this meme upon us...) improved on that by trying to count non-first commands in a pipeline -- showing a bug in all the other versions(!):
history \
| awk '{print $2}' \
| awk 'BEGIN {FS="|"}{print $1}' \
| sort \
| uniq -c \
| sort -n \
| tail \
| sort -rn
All of these variants put me in mind of my favorite Unix quote, now lost to the mists of time: In Unix there are a thousand ways to do any task -- all but one of them are wrong.
[An earlier version of this note appeared in Verilab's internal newsletter.]
