203

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?

2
  • 3
    Normally I use control-r to reverse-search in the command history of one bash. More convenient than history | grep unless you need a regex. Feb 5, 2018 at 11:24
  • 2
    @PeterCordes But that will only search in the history of that one terminal so it is going in the opposite direction of the question. ;)
    – Warkwark
    May 11, 2020 at 7:11

4 Answers 4

169

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:

2
  • 2
    well this kind of works. I tried some more testing and it seems to only work on the first command. does it work correctly for you?
    – Matt
    Oct 16, 2011 at 15:03
  • 1
    isn't histappend there by default? Sep 23, 2021 at 5:24
82

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.

13
  • 1
    Brilliant! Thanks. Wonder why those options aren't documented in man history... May 17, 2013 at 12:31
  • 15
    @artfulrobot: This command is a bash built-in so it is described in man bash. You can also use help history. Jul 2, 2014 at 9:32
  • 3
    I have my zsh configured to work like this: Each shell tracks its OWN history (and before that, the combined history), and every command is appended to combined history. This is different and better than always reloading history for every command for every shell, because I tend to have a different "thread of work" or "job" for each shell terminal. I think that is the difference between this with -r and -c vs just having -a.
    – Steven Lu
    Feb 25, 2015 at 9:40
  • 5
    The downside of history -c; history -r is that if you have another terminal open on the same computer, and switch to the other terminal to do something, press up, you'd see the last command from the previous terminal, not from this one. Very annoying.
    – R J
    Mar 16, 2019 at 19:28
  • 1
    @RJ 's comment is probably exactly why I'm getting these requests for sharing my setup. Thanks for the requests. Unfortunately it's close to a decade since I set stuff up (which was definitely nontrivial) and I'd need to actually dive back into determining the correct settings to get this behavior right. Absolutely worthy of a blog post though, but I'm not set up for blogging at the moment, been putting it off. I know there's an existing blog post out there where someone has clearly laid out how to get this right. Let me look for one..
    – Steven Lu
    May 11, 2020 at 13:09
55

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.

3
  • 2
    Brilliant! No more lost history when the connection gets dropped!
    – Tobia
    Jan 15, 2016 at 14:45
  • 1
    This is wonderful. By appending to the file and reading from file, it will share history across multiple terminals.
    – wisbucky
    Feb 20, 2018 at 19:45
  • For some reason it doesn't work for me. It works in one terminal, but not in the other. It seems that after it writes the history file, it fails to load new commands. I have no such problem with history -c;history -r
    – user502144
    Oct 18, 2023 at 12:53
18

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.

3
  • On my mac 10.13.6 it seemed it did not work without the shopt -s histappend. Also note I added it to my ~/.bash_profile Aug 28, 2018 at 0:51
  • Likely there's another setting somewhere in your system that disabled histappend, as that is the default behavior. I would look for it, but I don't have access to a Mac.
    – Guss
    Aug 28, 2018 at 5:13
  • 3
    Macs have never shipped with Bash 4 (even the new ones). Apple doesn't like GPLv3 which Bash switched to with Bash 4, so they stopped updating Bash on MacOS a long time ago. This is also why the new MacOS is switching to Zsh as the default shell. Long story short, if you want Bash 4 on your Mac, you have to install it yourself. Oct 30, 2019 at 17:12

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .