This is actually a really interesting behavior and I confess I have greatly underestimated the question at the beginning. But first the facts:
1. What works
The functionality can be achieved in several ways, though each works a bit differently. Note that, in each case, to have the history "transferred" to another terminal (updated), one has to press Enter in the terminal, where he/she wants to retrieve the history.
This has two drawbacks:
- At login (opening a terminal), the last command from the history file is read twice into the current terminal's history buffer;
- The buffers of different terminals do not stay in sync with the history file.
(Yes, no need for shopt -s histappend
and yes, it has to be history -c
in the middle of PROMPT_COMMAND
)
This version has also two important drawbacks:
- The history file has to be initialized. It has to contain at least one non-empty line (can be anything).
- The
history
command can give false output - see below.
[Edit]
"And the winner is..."
This is as far as it gets. It is the only option to have both erasedups
and common history working simultaneously.
This is probably the final solution to all your problems, Aahan.
2. Why does option 2 not seem to work (or: what really doesn't work as expected)?
As I mentioned, each of the above solutions works differently. But the most misleading interpretation of how the settings work comes from analysing the output of history
command. In many cases, the command can give false output. Why? Because it is executed before the sequence of other history
commands contained in the PROMPT_COMMAND
! However, when using the second or third option, one can monitor the changes of .bash_history
contents (using watch -n1 "tail -n20 .bash_history"
for example) and see what the real history is.
3. Why option 3 is so complicated?
It all lies in the way erasedups
works. As the bash manual states, "(...) erasedups
causes all previous lines matching the current line to be removed from the history list before that line is saved". So this is really what the OP wanted (and not just, as I previously thought, to have no duplicates appearing in sequence). Here's why each of the history -.
commands either has to or can not be in the PROMPT_COMMAND
:
history -n
has to be there before history -w
to read from .bash_history
the commands saved from any other terminal,
history -w
has to be there in order to save the new history to the file after bash has checked if the command was a duplicate,
history -a
must not be placed there instead of history -w
, because it will add to the file any new command, regardless of whether it was checked as a duplicate.
history -c
is also needed because it prevents trashing the history buffer after each command,
and finally, history -r
is needed to restore the history buffer from file, thus finally making the history shared across terminal sessions.
Be aware that this solution will mess up the history order by putting all history from other terminals in front of the newest command entered in the current terminal. It also does not delete duplicate lines already in the history file unless you enter that command again.
The erasedups
should do what you want in regard to the duplicates - just note that erasing duplicates is triggered at the moment of appending a new entry to the history and that it erases all the old occurrences of a command, leaving just the most recent.
Answering the question "How can I have the history be exactly how it is before I logout?"
The way I see it, this can be useful only once in a while. (Otherwise why would you use history at all?) You can do it by issuing
history -c; history -r
This clears all the history entries kept currently in memory and then re-reads the whole history from the history-file. So all the commands you issued since logging into the current shell session are forgotten. I find it quite useful in situations when I do a lot of testing (many similar commands, but not really duplicates) and then don't want to have my history garbaged by that - so I have an alias for it in my .bashrc
:
alias hrr='history -c; history -r'
(hrr
to be remembered as "history re-read").
Best Answer
You could ignore the builtin history mechanism and abuse $PROMPT_COMMAND to write history any way you wanted. Some people keep a directory of history files, one for each shell/date/hostname, etc. Approximately something like this:
obviously embellish with dates, times, whatever...