I use Bash’s PROMPT_COMMAND variable:
The value of the variable PROMPT_COMMAND is examined just before Bash prints each primary prompt. If PROMPT_COMMAND is set and has a non-null value, then the value is executed just as if it had been typed on the command line.
The source code should be pretty straight forward, but if not, please ask in the comments. Put this in your .bashrc or similar:
# per-directory Bash history
function check_for_local_history {
local last_command=`history 1`
local last_command=${last_command:27} # this depends on HISTTIMEFORMAT
function main {
if changing_directory; then
if found_local_history_file; then
use_history_file $PWD/.bash_history
else
use_history_file ~/.bash_history
fi
fi
}
function changing_directory {
is_cd_nothing || is_cd_something || is_a_cd_alias
}
function is_cd_nothing {
[ ${#last_command} -eq 2 -a "${last_command:0:2}" = "cd" ]
}
function is_cd_something {
[ ${#last_command} -gt 2 -a "${last_command:0:3}" = "cd " ]
}
function is_a_cd_alias {
local cd_aliases=`alias | grep "='cd " | grep -P -o '[a-z]+(?==)'`
echo $cd_aliases | grep -q "\<$last_command\>"
}
function found_local_history_file {
[ -e .bash_history ]
}
function use_history_file {
history -w
history -c
export HISTFILE=$1
history -r
}
main
}
PROMPT_COMMAND="check_for_local_history"
This implementation will unnecessarily re-read "global" history file ~/.bash_history every time you change between non-local-history directories.
Also it won't detect commands like
mydir
which is equivalent tocd mydir
whenautocd
is active, or recursive aliases, or other non-trivial things.Hence I think the better way is to remember
$PWD
in a global variable and re-check it every time, and also don't do history re-reading stuff if new desired$HISTFILE
did not change (even when the directory changed).Here is my implementation, heavily inspired by yours: