i want my command history to already be saved if my system crashes (eg the plug is pulled, or a vm is reset).
it helps to put history -a in PROMPT_COMMAND, but it still doesn’t occur until the command completes, so in a crash much of the history was written, but not any commands that were running when it crashed.
so to write commands to history before executing them it seems like it ought to be good to put $(history -a) in PS0
but the result of that is that commands get written to history multiple times.
why? and what to do instead?
is it a bug in bash or what am i missing? shouldn’t history -a just do nothing if the history is already written?
i wonder if using PS0 is seeming to cause trouble because that’s at the point in time when bash is busy processing the command, and perhaps it’s mishandling when the history write call returns “interrupted system call”, such that instead of allowing the call to proceed it mishandles by restarting the call instead?
Provide complete transcript of your interactive session (with commands you entered) and show corresponding history entries, as well as the value of prompt you set.
ok i’m guessing that when history -a is inside $() the subshell writes the history but outside the $() subshell doesn’t know those history lines were already written! so using PS0 doesn’t work. maybe there’s a trap to use?
you asked for:
.bashrc
PS0='$(echo -n %)'
PS1=\<$SHLVL'>$ '
transcript
<1>$ mb .bash_history _/.bash_hi0
%(.bash_history -> _/.bash_hi0)
<1>$ bash
%<2>$ echo a
%a
<2>$ echo b
%b
<2>$ history
% 1 2023-09-23Sat03:47:39 echo a
2 2023-09-23Sat03:47:40 echo b
3 2023-09-23Sat03:48:02 history
<2>$ exit
add PS0='$(history -a;echo -n %)' to .bashrc
<1>$ bash
%<2>$ echo c
%c
<2>$ echo d
%d
<2>$ history
% 1 2023-09-23Sat03:47:39 echo a
2 2023-09-23Sat03:47:40 echo b
3 2023-09-23Sat03:48:02 history
4 2023-09-23Sat03:48:34 echo c
5 2023-09-23Sat03:48:35 echo d
6 2023-09-23Sat03:48:40 history
<2>$ exit
<1>$ bash
%<2>$ history
% 1 2023-09-23Sat03:47:39 echo a
2 2023-09-23Sat03:47:40 echo b
3 2023-09-23Sat03:48:02 history
4 2023-09-23Sat03:48:34 echo c
5 2023-09-23Sat03:48:34 echo c
6 2023-09-23Sat03:48:35 echo d
7 2023-09-23Sat03:48:34 echo c
8 2023-09-23Sat03:48:35 echo d
9 2023-09-23Sat03:48:40 history
10 2023-09-23Sat03:48:34 echo c
11 2023-09-23Sat03:48:35 echo d
12 2023-09-23Sat03:48:40 history
<2>$ exit
.bash_history
#1695458859
echo a
#1695458860
echo b
#1695458882
history
#1695458914
echo c
#1695458914
echo c
#1695458915
echo d
#1695458914
echo c
#1695458915
echo d
#1695458920
history
#1695458914
echo c
#1695458915
echo d
#1695458920
history
add PROMPT_COMMAND=history\ -a PS0='$(echo -n %)' to .bashrc
<1>$ mb .bash_history _/.bash_hi1
%(.bash_history -> _/.bash_hi1)
<1>$ bash
%<2>$ echo a
%a
<2>$ echo b
%b
<2>$ history
% 1 2023-09-23Sat04:23:17 echo a
2 2023-09-23Sat04:23:21 echo b
3 2023-09-23Sat04:23:23 history
<2>$ exit
%exit
<1>$
.bash_history
#1695460997
echo a
#1695461001
echo b
#1695461003
history
#1695461036
exit
You may consider using zsh which is sufficiently compatible to bash so no huge amount of learning is needed and probably is even better suited as interactive shell. It has explicit option INC_APPEND_HISTORY which does exactly what you want: “new history lines are added to the $HISTFILE incrementally (as soon as they are entered)”.
I do not know. I never made this detailed comparison (and was never interested in doing it). I suppose you could ask bard, whoever he is. But I can tell that modern zsh most certainly has cd command and it had it when I started to use it (which was 20+ years ago).
Also, zsh can be started using bash alias and is believed to behave reasonably compatible in this case.
i’d had my eye on zsh but so far hadn’t thrown any time to it, well INC_APPEND_HISTORY indeed appears to do just what i wanted, did a bit of work to make it work to just softlink .zshrc to .bashrc using conditionals to set the prompt, INC_APPEND_HISTORY, et al, happy to be trying on zsh, changing /etc/passwd to make it my login now.
well i quite like that incappendhistory appends before executing the command, and i wish bash could do that, because zsh has some serious shortcomings eg Zsh can’t resume functions?
ok bash can append history before execute, with this in .bashrc:
shopt -s histappend
PROMPT_COMMAND='history -a
trap appendb4exec debug'
appendb4exec(){ trap "" debug #after appending history no need for trap until next prompt
history -a;}
in my .bashrc actually i have a function call there that does a bit more than just append the history, in the case of a new window it shows some stuff on screen and in a history header, but yeah as posted it looks entirely redundant.