214

I often open lots and lots of terminals (right now, I have seven open on this workspace) and I often search history with grep to find a command I've just written recently, but I don't want to hunt down the terminal and then scroll up and hunt for it.

Sometimes my terminals close without exit, and everything I've written in them is lost. Sometimes, I needed something I'd written in a terminal that was killed.

Is there a way to make it so that each terminal writes to .bash_history immediately? Or at least once a minute, or something like that?

Matt
  • 10,201

5 Answers5

176

A simple solution is detailed in Update Bash History in Realtime.

It says to put those commands in the .bashrc config:

shopt -s histappend
PROMPT_COMMAND="history -a;$PROMPT_COMMAND"

The first command changes the history file mode to append and the second configures the history -a command to be run at each shell prompt. The -a option makes history immediately write the current/new lines to the history file.

From man bash:

If the histappend shell option is enabled (see the description of shopt under SHELL BUILTIN COMMANDS below), the lines are appended to the history file, otherwise the history file is overwritten.

Related for Zsh:

mario
  • 3,530
85

Try putting this into your .bashrc:

shopt -s histappend                      # append to history, don't overwrite it
export PROMPT_COMMAND="history -a; history -c; history -r; $PROMPT_COMMAND"

Credit here: https://stackoverflow.com/questions/103944/real-time-history-export-amongst-bash-terminal-windows/3055135

history -c clears the history of the running session. This will reduce the history counter by the amount of $HISTSIZE. history -r read the contents of $HISTFILE and insert them in to the current running session history. This will raise the history counter by the amount of lines in $HISTFILE.

I think it means that the commands are available almost immediately (you have one terminal, write echo 1, second terminal echo 2, first echo 3 and upon pressing down arrow twice, you should have echo 2 available. You must issue a command in a given terminal to have access to what has been written.

7ochem
  • 191
sup
  • 4,964
58

I have a large history file with about 100000 entries, and the variants that clear the history list and read the whole history file (using history -c and history -r) introduce a noticeable (maybe 0.2 second) delay before the prompt is displayed. Using history -n so that only new lines are read from the history file is faster:

shopt -s histappend
PROMPT_COMMAND='history -a;history -n'

PROMPT_COMMAND does not have to be exported because it is a shell variable.

nisetama
  • 791
21

A note for all other answers (which are basically the same thing):

Setting PROMPT_COMMAND="history -a;$PROMPT_COMMAND" in the .bashrc (or friends) is enough.

Also, you can manually run history -a whenever you want to "snapshot" the history in the current session.

The command shopt -s histappend is not needed because history -a always appends new lines to the file and never overwrites it. Also, at least as of Bash 4, histappend is the default behavior.

Guss
  • 3,775
1

TL;DR

Add the following to .bashrc:

PS0="$PS0"'$(history -a)'
PROMPT_COMMAND+=( 'history -n' )

(as of bash 5.0)


Long answer

Saving history

Other answers use PROMPT_COMMAND, which only appends a command to the history file after the command is done running. Ideally we would like to write the command to file immediately after entering it. Bash 4.4 added PS0, which is interpreted before a command is executed:

New prompt string: PS0. Expanded and displayed by interactive shells reading a complete command but before executing it.

Source: CHANGES file in the Bash tarball.

Thus, we can extend PS0, being careful to literally append the string $(history -a) so that the execution of the history command is delayed until bash expands PS0.

PS0="$PS0"'$(history -a)'

Since history -a doesn't have any output, we shouldn't need to worry about its output becoming part of the prompt.

Loading history

On the other hand, loading history is still most useful immediately before we start entering a new command. However, note that as of Bash 5.0, PROMPT_COMMAND is intended as an array variable (although using it as a single string still works):

PROMPT_COMMAND: can now be an array variable, each element of which contain a command to be executed like a string PROMPT_COMMAND variable.

Source: same changelog.

Thus, the proper way to add a new command to it uses Bash's array syntax:

PROMPT_COMMAND+=( 'history -n' )
just-max
  • 111