Skip to content

Instantly share code, notes, and snippets.

@jan-warchol
Last active February 4, 2024 04:52
Show Gist options
  • Star 47 You must be signed in to star a gist
  • Fork 13 You must be signed in to fork a gist
  • Save jan-warchol/89f5a748f7e8a2c9e91c9bc1b358d3ec to your computer and use it in GitHub Desktop.
Save jan-warchol/89f5a748f7e8a2c9e91c9bc1b358d3ec to your computer and use it in GitHub Desktop.
Synchronize history across bash sessions
# 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
# 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
@babanga
Copy link

babanga commented Feb 3, 2024

Is there a way to record only direct inputs? Now it seems it catches all inputs, history file is full of mc's outputs like:
cd "printf '%b' '\0057home"

@babanga
Copy link

babanga commented Feb 3, 2024

Still trying to fix this to use with tmux. Now it catches all the commands sent from random apps, but later this breaks the input ending up with:
$ mc
$ ls -la
$ ls -latop
can't remove that ^ ls -la
upd: Ok, that part probably was caused by cyd01/KiTTY and fixed by changing termtype to tmux-256color

MC's internal commands has a leading space so it won't be saved in history, but it still gets saved. Fixed it by checking for leading space and exiting the function. But is there a better solution to rrecord only user inputs?

update_history () {
    lastCmd=$(fc -lnr | head -n1)
    # clean the spaces left by fc
    lastCmdReal=${lastCmd:2}
    # remove all leading spaces
    lastCmdRealClean=${lastCmd##+([[:space:]])}

    if [[ "$lastCmdReal" == " $lastCmdRealClean"  ]]; then
       return 0
    fi

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment