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!
No related posts.
Related posts brought to you by Yet Another Related Posts Plugin.










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()
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()
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.
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?
@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.
You can try the code below found here – didn’t try it but it looks promising:
run BASH built-in commands in Python
from subprocess import Popen, PIPE, STDOUT
shell_command = 'bash -i -c "history -r; history"'
event = Popen(shell_command, shell=True, stdin=PIPE, stdout=PIPE,
stderr=STDOUT)
output = event.communicate()