How to get shared bashed history among different tabs

I used the answer in https://unix.stackexchange.com/a/1292/41729 to enable real-time shared history among separate bash terminals. As explained in the answer above, this is achieved by adding:

# avoid duplicates..
export HISTCONTROL=ignoredups:erasedups  
# append history entries..
shopt -s histappend

# After each command, save and reload history
export PROMPT_COMMAND="history -a; history -c; history -r; $PROMPT_COMMAND"

This works fine if the bash shells are separate (e.g. opening different bash terminals using CTRL+ALT+T. However it doesn't work if I use tabs (from an open terminal `CTRL+SHIFT+T) rather than new windows. Why this difference in behaviour? How can I share the bash history also among various tabs?

UPDATE: I noticed an unusual behaviour: if I type CTRL+C then the last command typed in any of the other terminals (both a tab or not) is correctly displayed. It is like if the CTRL+C forces a flush of the history so that then it is correctly shared.

As an example the outputs (T1 denotes terminal 1 and T2 terminal 2):

T1:
ls -lah <enter>
# the list of files and directory is shown

T2:
cd Documents <enter>

T1:
<up> (i.e. I press the up arrow)
ls -lah #i.e the last command in terminal 1 is shown rather than the last of terminal 2
^C (i.e. I press CTRL+C)
<up>
cd Documents #the last command issued in terminal 2 is correctly displayed

Hope this can offer any hint!


Solution 1:

It looks like you're trying to access the other terminal's history before the sync takes place. PROMPT_COMMAND is executed right before a new prompt is printed, i.e., after you run a command and before you type the next command. So it won't happen right away in T1; you have to cause a new prompt to be displayed.

To test this, try this variant on your steps (I added an extra <enter> in T1):

T1:
ls -lah <enter>
# the list of files and directory is shown

T2:
cd Documents <enter>

T1:
<enter>
<up> (i.e. I press the up arrow)

With this extra press of enter, you get a new prompt, which runs PROMPT_COMMAND and syncs your history, and so I would expect this up arrow to retrieve the cd instead of the ls, as you wanted. Unfortunately, I don't think there is a way to make the sync happen instantaneously in all terminals without running any commands as you seem to want; effectively this would require all of your login sessions to be synchronizing their history lists continuously all the time, which would be a huge waste of CPU and disk throughput.

Solution 2:

I asked the same question and here is the answer I came up with....

HISTSIZE=9000
HISTFILESIZE=$HISTSIZE
HISTCONTROL=ignorespace:ignoredups

history() {
  _bash_history_sync
  builtin history "$@"
}

_bash_history_sync() {
  builtin history -a         #1
  HISTFILESIZE=$HISTSIZE     #2
  builtin history -c         #3
  builtin history -r         #4
}

PROMPT_COMMAND=_bash_history_sync

Solution 3:

add that lines to your .bashrc file

# avoid duplicates..
export HISTCONTROL=ignoredups:erasedups  
# append history entries..
shopt -s histappend

trap 'history -r' USR1 
export PROMPT_COMMAND="history -a ; history -c; ps a | awk '/ bash$/ {system (\"kill -USR1 \" \$1)}'; $PROMPT_COMMAND"

note:

Initially I did my test bay sending USR1 signal to bash with killall, later I thought to use a uniquee shell name, a bash copy named testshell, to avoid killing my own shells that could run (cron processes for instance) but strangelly that was not working.

The killall was not selective enough, I replaced it with a script that kills only the bash processes tight to a tty (ps a reports only processes tied to a tty)

Do not forget to restart your session to have a fresh PROMPT_COMMAND, when I was testing I saw many of my previous test stacked inside PROMPT_COMMAND.