- Adding information to history
- Making the prompt a little more likeable
As we all know, sometimes you enter a command in bash, but then find that you entered it a lot and need to look at the different ways you entered it. So there's the history; type "history" into the prompt, and you'll see all your commands (for some time, its limited in size by the HISTSIZE environment variable).
But frequently, we might want more information than merely the command itself. Such as when it was entered, who entered it, on what terminal in what process.
After searching around for a while, I found this script, and decided to enhance it:
log_history() {# Detailed history log of shell activities, including time stamps, working directory etc.## Based on 'hcmnt' by Dennis Williamson - 2009-06-05 - updated 2009-06-19# (http://stackoverflow.com/questions/945288/saving-current-directory-to-bash-history)## Add this function to your '~/.bashrc':## Set the bash variable PROMPT_COMMAND to the name of this function and include# these options:## e - add the output of an extra command contained in the histentrycmdextra variable# h - add the hostname# y - add the terminal device (tty)# n - don't add the directory# t - add the from and to directories for cd commands# l - path to the log file (default = $HOME/.bash_log)# ext or a variable## See bottom of this function for examples.## make sure this is not changed elsewhere in '.bashrc';# if it is, you have to update the reg-ex's belowexport HISTTIMEFORMAT="[%F %T] ~~~ "local script=$FUNCNAMElocal histentrycmd=local cwd=local extra=local text=local logfile="$HOME/.bash_log"local hostname=local histentry=local histleader=local datetimestamp=local histlinenum=local options=":hyntel:"local option=OPTIND=1local usage="Usage: $script [-h] [-y] [-n|-t] [-e] [text] [-l logfile]"local ExtraOpt=local NoneOpt=local ToOpt=local tty=local ip=# *** process options to set flags ***while getopts $options optiondocase $option inh ) hostname=$HOSTNAME;;y ) tty=$(tty);;n ) if [[ $ToOpt ]]thenecho "$script: can't include both -n and -t."echo $usagereturn 1elseNoneOpt=1 # don't include pathfi;;t ) if [[ $NoneOpt ]]thenecho "$script: can't include both -n and -t."echo $usagereturn 1elseToOpt=1 # cd shows "from -> to"fi;;e ) ExtraOpt=1;; # include histentrycmdextral ) logfile=$OPTARG;;: ) echo "$script: missing filename: -$OPTARG."echo $usagereturn 1;;* ) echo "$script: invalid option: -$OPTARG."echo $usagereturn 1;;esacdonetext=($@) # arguments after the options are saved to add to the commenttext="${text[*]:$OPTIND - 1:${#text[*]}}"# add the previous command(s) to the history file immediately# so that the history file is in sync across multiple shell sessionshistory -a# grab the most recent command from the command historyhistentry=$(history 1)# parse it outhistleader=`expr "$histentry" : ' *\([0-9]* \[[0-9]*-[0-9]*-[0-9]* [0-9]*:[0-9]*:[0-9]*\]\)'`histlinenum=`expr "$histleader" : ' *\([0-9]* \)'`datetimestamp=`expr "$histleader" : '.*\(\[[0-9]*-[0-9]*-[0-9]* [0-9]*:[0-9]*:[0-9]*\]\)'`histentrycmd=${histentry#*~~~ }# protect against relogging previous command# if all that was actually entered by the user# was a (no-op) blank line#if [[ -z $__PREV_HISTLINE || -z $__PREV_HISTCMD ]]#then# new shell; initialize variables for next command# export __PREV_HISTLINE=$histlinenum# export __PREV_HISTCMD=$histentrycmd# return#elif [[ $histlinenum == $__PREV_HISTLINE && $histentrycmd == $__PREV_HISTCMD ]]#then# no new command was actually entered# return#else# new command entered; store for next comparison# export __PREV_HISTLINE=$histlinenum# export __PREV_HISTCMD=$histentrycmd#fiif [[ -z $NoneOpt ]] # are we adding the directory?thenif [[ ${histentrycmd%% *} == "cd" || ${histentrycmd%% *} == "jd" ]] # if it's a cd command, we want the old directorythen # so the comment matches other commands "where *were* you when this was done?"if [[ -z $OLDPWD ]]thenOLDPWD="$HOME"fiif [[ $ToOpt ]]thencwd="$OLDPWD -> $PWD" # show "from -> to" for cdelsecwd=$OLDPWD # just show "from"fielsecwd=$PWD # it's not a cd, so just show where we arefifiif [[ $ExtraOpt && $histentrycmdextra ]] # do we want a little something extra?thenextra=$(eval "$histentrycmdextra")fi# strip off the old ### comment if there was one so they don't accumulate# then build the string (if text or extra aren't empty, add them with some decoration)histentrycmd="${datetimestamp} ${text:+[$text] }${tty:+[$tty] } [PPID:$PPID] ${ip:+[$ip]} ${extra:+[$extra] }~~~ ${hostname:+$hostname:}$cwd ~~~ ${histentrycmd# * ~~~ }"# save the entry in a logfileecho "$histentrycmd" >> $logfile || echo "$script: file error." ; return 1} # END FUNCTION _loghistory
As long as this is somewhere that will be available to every terminal, you'll be in business.
Now, one thing I don't like is silent failure. If a command fails, it should output something. Most of the time, this occurs, but sometimes it does not. If you check the result, you can see this explicitly, but who wants to type that all the time? So I came up with this:
PROMPT_COMMAND='PS1="\033[0;33m\d \@ || \u\n\`if [[ \$? = "0" ]]; then echo "\\[\\033[32m\\]"; else echo "\\[\\033[31m\\]"; fi\`[\w]\$ \[\033[0m\] "; echo -ne "\033]0;`hostname -s`:`pwd`; `log_history -h -y -t -e -l ~/.bash_log`\007 "'
Now your prompt will be shorter for your commands, show you the time of each previous command (if you should ever need that) and turn red when things fail.