tail -f findings.out

« BlackBerry Storm: Thoughts and Tips

Convenient OS and hardware summary information »

Improving command line efficiency via Bash history

If you work in Bash with any frequency, hopefully you collect aliases to make your life easier. Complicated and highly useful commands should be saved and re-used so that you can get to the information you need in the least possible time. However, some longish commands might slip by your notice and not get changed into aliases.

In that spirit, I have created a function to provide better visibility into your current Bash history. It prints out the current top ten most common commands in your history and how often each has been used. This in itself is pretty common, and often implemented via something like this.

My script also adds the percentage of each count out of your total history and statistics like date range. It also prints commands in red if they are 10 characters or more in length. This was an arbitrary selection, adjust as you see fit. The basic idea is that when you run it, you can easily see if you have been running longish commands rather often, providing you with excellent candidates for alias formation.

Important caveat: This function pulls out various columns of history’s output for processing and presentation. These are entirely dependent on the format of your history. My history is of the form:

1
HISTORY_NUMBER YYYY-MM-DD HH:MM:SS - COMMAND

which I find most useful. How to set this up is described in this post. If you have your history set up differently (and decide not to switch to my lovely format:-)), please adjust the columns as needed. It should be pretty easy to figure out. Current code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
function cmds () {
    # This lets us iterate per line instead of over count then cmd:
    export IFS=$'\n'
    export HISTORY_LENGTH=`history | wc -l`
    export TOP_TEN_CMDS=`history | awk '{print $5}' | sort | uniq -c | sort -n | tail -n 10`
    export START_DATE=`history | awk '{print $2}' | sort | uniq | sort -r | tail -n 1`
    export END_DATE=`history | awk '{print $2}' | sort | uniq | sort | tail -n 1`
    echo -e "\033[34mTop ten most used commands (Count, Command, % of history):\033[0m "
    # Show the 10 most common commands, with percentage of total, in red if 10 chars or more.
    for CMD in $TOP_TEN_CMDS; do
        export CMD_COUNT=`echo $CMD | awk '{print $1}'`
        export CMD_PERCENT=`echo "scale=4; $CMD_COUNT / $HISTORY_LENGTH" | bc`
        export SHORT_CMD=`echo $CMD | awk '{print $2}'`
        if [ ${#SHORT_CMD} -ge 10 ]; then
            echo -e "\033[31m * $CMD ($CMD_PERCENT%)\033[0m - Length ${#SHORT_CMD}, might want to form an alias for this."
        else
            echo " * $CMD ($CMD_PERCENT%)"
        fi
    done
    echo -e "\033[34m$HISTORY_LENGTH lines in history from $START_DATE to $END_DATE.\033[0m"
    unset IFS
}

This will produce output (depending on your history format, see caveat above) like:

Side note: I tried moving this into python once it began to get a little complicated. The problem I ran into was that history isn’t a command, it’s a bash shell builtin! Thus, when I tried things like:

1
2
3
4
import os, subprocess, commands
os.system('history')
subprocess.call('history')
commands.getoutput('history')

I got back “command not found” and the like. I currently don’t know how to call bash shell builtins from Python, so if anyone has any insight, please share!

Share and Enjoy:
  • email
  • LinkedIn
  • Slashdot
  • StumbleUpon
  • Technorati
  • Netvibes

Post to Twitter Post to Delicious Post to Digg Post to Reddit

Possibly Related (no promises):

  1. Get useful image information on the command line
  2. Easily sum matching file line counts
  3. Useful Bash functions to determine OS and more
  4. Viewing all users on a Linux system

Related posts brought to you by Yet Another Related Posts Plugin.

Tags: , , ,
December 29, 2008 - 1:19 PM
5 comments »
  • anonim

    December 29, 2008 | 3:05 PM

    AFAIK history just prints the contents of ~/.bash_history and it’s line number, so you could write that in python, a very quick and dirty solution:

    import os

    def do_history():
    h = open(’%s/.bash_history’ % os.environ['HOME'])
    counter = 0
    for line in h.readlines():
    counter += 1
    print counter, #!/usr/bin/python
    import os

    def do_history():
    h = open(’%s/.bash_history’ % os.environ['HOME'])
    counter = 0
    for line in h.readlines():
    counter += 1
    print counter, line.replace(’\n’,”)

    if __name__ == ‘__main__’:
    do_history()

  • anonim

    December 29, 2008 | 3:07 PM

    Sorry but I managed to blow the post, here we go again:

    import os

    def do_history():
    h = open(’%s/.bash_history’ % os.environ['HOME'])
    counter = 0
    for line in h.readlines():
    counter += 1
    print counter, line.replace(’\n’,”)

    if __name__ == ‘__main__’:
    do_history()

  • Samuel Huckins

    December 29, 2008 | 3:44 PM

    I wanted to steer clear of just using .bash_history because that doesn’t take into account the format and other options declared in .bashrc and .bash_profile, as the history builtin does. So if you filter out certain commands, or do anything else custom, the file won’t reflect that, which seemed sub-optimal to me.

  • Hugo Heden

    February 16, 2009 | 6:28 AM

    Lovely!

    Rookie question, sorry:

    Do you suggest to put that function in ~/.bashrc ? Or rather as a separate script in ~/bin ?

    And the what about the *alias* commands?

  • Samuel Huckins

    February 16, 2009 | 9:16 AM

    @Hugo: I am on the fence about where to put this function. Right now I keep it in my ~/.bashrc. If it were any longer, I would likely pull it out into my directories of personal scripts, symlinked somewhere system-appropriate.

    The alias commands I would definitely keep in ~/.bashrc, so that all my defined aliases are in one intuitive place.

Leave a reply

Subscribe without commenting

Twitter links powered by Tweet This v1.6.1, a WordPress plugin for Twitter.