Append bash history sooner

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

precmd and preexec don’t appear to work, should i expect them in opensuse tumbleweed bash 5.2.15(1)-release?

That’s probably it.

What makes you think it was supposed to work?

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)”.

1 Like

found a github that adds them to bash, not immediately clear what bash versions might use it.

do you use zsh? how’s it go? bard claims cd vs chdir, $HOME vs $HOMEZSH, and ! incompatibilities exist, do you confirm those? what do you run into?

google does not confirm “HOMEZSH”, are there fragments of reality in any of the 3 incompatibilities bard claimed?

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;}

Any reason for this additional invocation? I briefly tested it, and it seems to work without. What does not work in this case?

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.