diff --git a/sync-history.sh b/sync-history.sh new file mode 100755 index 0000000..6ea52a1 --- /dev/null +++ b/sync-history.sh @@ -0,0 +1,58 @@ +# Synchronize history between bash sessions +# +# Make history from other terminals available to the current one. However, +# don't mix all histories together - make sure that *all* commands from the +# current session are on top of its history, so that pressing up arrow will +# give you most recent command from this session, not from any session. +# +# Since history is saved on each prompt, this additionally protects it from +# terminal crashes. + + +# keep unlimited shell history because it's very useful +export HISTFILESIZE=-1 +export HISTSIZE=-1 +shopt -s histappend # don't overwrite history file after each session +export HISTFILE=~/.bash/.bash_history + +# on every prompt, save new history to dedicated file and recreate full history +# by reading all files, always keeping history from current session on top. +update_history () { + history -a ${HISTFILE}.$$ + history -c + history -r # load common history file + # load histories of other sessions + for f in `ls ${HISTFILE}.[0-9]* 2>/dev/null | grep -v "${HISTFILE}.$$\$"`; do + history -r $f + done + history -r "${HISTFILE}.$$" # load current session history +} +if [[ "$PROMPT_COMMAND" != *update_history* ]]; then + export PROMPT_COMMAND="update_history; $PROMPT_COMMAND" +fi + +# merge session history into main history file on bash exit +merge_session_history () { + if [ -e ${HISTFILE}.$$ ]; then + cat ${HISTFILE}.$$ >> $HISTFILE + \rm ${HISTFILE}.$$ + fi +} +trap merge_session_history EXIT + + +# detect leftover files from crashed sessions and merge them back +active_shells=$(pgrep `ps -p $$ -o comm=`) +grep_pattern=`for pid in $active_shells; do echo -n "-e \.${pid}\$ "; done` +orphaned_files=`ls $HISTFILE.[0-9]* 2>/dev/null | grep -v $grep_pattern` + +if [ -n "$orphaned_files" ]; then + echo Merging orphaned history files: + for f in $orphaned_files; do + echo " `basename $f`" + \cat $f >> $HISTFILE + \rm $f + done + echo "done." +fi +