7

Following the answer:

When closing multiple bash instances at the same time, there is a known race condition that may cause the history to be cleared. This occurs because there is no locking used when the bash history file is written.

How can I prevent against this cause of bash history purge?

I use i3wm and I think that it happens mostly when I shutdown the computer before I manually close urxvt terminals. The command used (via keybind) for shutdown is systemctl poweroff.

kravemir
  • 4,174

3 Answers3

3

The source of the race condition is because bash only writes the history file as the shell exits. Plus it will over write the existing history file if multiple shells are running, only the last to exit will dominate the history.

So one solution is to write history out, after EVERY command. There or some negative consequences to this, such as you'll be able to up arrow history events occurring in other windows, and therefor will expose to all open shells (that you own) what commands you just ran. The most likely place this will bite you is if you are doing a repetitive set of commands, like 'up arrow N times, then hit enter' over and over again. If in a closed window a background process ends, then suddenly you'll need to pay closer attention what command is really 'up arrow N+1 times' risking running the wrong command.

To turn 'history on with every command' try adding these to you .bashrc (number of lines of history to store are just examples, you can change them for your comfort)

HISTFILESIZE=400000000
HISTSIZE=10000
PROMPT_COMMAND="history -a"
export HISTSIZE PROMPT_COMMAND

shopt -s histappend
Cosmo F
  • 169
  • 1
    Interesting idea, but I don't want to share histories between running sessions. Would it be possible without affecting already made sessions? – kravemir Mar 14 '15 at 09:10
1

When you start bash, it will warn you if your history has been deleted (as measured by line count). If the history has not been deleted, it will be backed up.

~/.bashrc

# backup history/warn about deleted history
if (( $(wc -l < ~/.bash_history) < 1100 ))
then
    echo "#########################"
    echo ".bash_history was cleared"
    echo "#########################"
else
    cp ~/.bash_history ~/.bash_history.back
fi
Rui F Ribeiro
  • 56,709
  • 26
  • 150
  • 232
Evidlo
  • 171
  • 1
    (1) Can you explain how this answers the question?  (2) The question is about the risks of doing asynchronous file modification without benefit of a synchronization protocol like file locking.  This answer seems to be throwing gasoline on the fire, by writing the .bash_history.back file in every new bash process, in a context where the user may be opening multiple new windows at the same time. – Scott - Слава Україні May 31 '19 at 04:02
  • @Scott: (2) I really don't think the asker had any of that in mind. They just want to stop losing their history. (1) While I agree this solution doesn't answer the question directly (i.e. How can this problem be prevented?), this does help mitigate the damage. As for making the problem worse, I don't see an issue. My .bash_history is 100k lines and backing it up it adds 8ms to the startup time. Even more, the race condition is caused when the bash instances are closed, not started. – Evidlo May 31 '19 at 04:31
  • @Evidlo added to my .bashrc thank you – somethingSomething May 31 '19 at 04:55
0

My solution was to merge in-memory history with the on-disk history, before logging out...

Note only that it does so while preserving history timestamp ordering, and command order within those timestamps.

Optionally removing unique commands (even if multi-line), and/or removing (cleaning out) simple and/or sensitive commands, according to defined perl RE's. Adjust to suit!

This is the result... https://antofthy.gitlab.io/software/history_merge.bash.txt

I source this script either 'on demand' via a shell alias 'hc' (for history clean), and from the ".bash_logout" profile, to merge/clean before exiting.

Enjoy.

anthony
  • 610