Better Bash history

By default, the Bash shell keeps the history of your most recent session in the .bash_history file, and the commands you’ve issued in your current session are also available with a history call. These defaults are useful for keeping track of what you’ve been up to in the shell on any given machine, but with disks much larger and faster than they were when Bash was designed, a little tweaking in your .bashrc file can record history more permanently, consistently, and usefully.

Append history instead of rewriting it

You should start by setting the histappend option, which will mean that when you close a session, your history will be appended to the .bash_history file rather than overwriting what’s in there.

shopt -s histappend

Allow a larger history file

The default maximum number of commands saved into the .bash_history file is a rather meager 500. If you want to keep history further back than a few weeks or so, you may as well bump this up by explicitly setting $HISTSIZE to a much larger number in your .bashrc. We can do the same thing with the $HISTFILESIZE variable.

HISTFILESIZE=1000000
HISTSIZE=1000000

The man page for Bash says that HISTFILESIZE can be unset to stop truncation entirely, but unfortunately this doesn’t work in .bashrc files due to the order in which variables are set; it’s therefore more straightforward to simply set it to a very large number.

If you’re on a machine with resource constraints, it might be a good idea to occasionally archive old .bash_history files to speed up login and reduce memory footprint.

Don’t store specific lines

You can prevent commands that start with a space from going into history by setting $HISTCONTROL to ignorespace. You can also ignore duplicate commands, for example repeated du calls to watch a file grow, by adding ignoredups. There’s a shorthand to set both in ignoreboth.

HISTCONTROL=ignoreboth

You might also want to remove the use of certain commands from your history, whether for privacy or readability reasons. This can be done with the $HISTIGNORE variable. It’s common to use this to exclude ls calls, job control builtins like bg and fg, and calls to history itself:

HISTIGNORE='ls:bg:fg:history'

Record timestamps

If you set $HISTTIMEFORMAT to something useful, Bash will record the timestamp of each command in its history. In this variable you can specify the format in which you want this timestamp displayed when viewed with history. I find the full date and time to be useful, because it can be sorted easily and works well with tools like cut and awk.

HISTTIMEFORMAT='%F %T '

Use one command per line

To make your .bash_history file a little easier to parse, you can force commands that you entered on more than one line to be adjusted to fit on only one with the cmdhist option:

shopt -s cmdhist

Store history immediately

By default, Bash only records a session to the .bash_history file on disk when the session terminates. This means that if you crash or your session terminates improperly, you lose the history up to that point. You can fix this by recording each line of history as you issue it, through the $PROMPT_COMMAND variable:

PROMPT_COMMAND='history -a'

23 thoughts on “Better Bash history

  1. Hi, thanks a lot for these useful tips, I already knew some but not all. Could tell me what was the other way to update the file .bashrc, in addition to “source. bashrc”, I can’t remember! Congratulations for the website, is fantastic.

    PS: and how to run commands without the predetermined alias?

    • I’m glad it was helpful. You can run .sh files within your environment with just a period:

      $ . .bashrc
      

      One way of bypassing aliases is to escape the first letter of your command, e.g. if you have ls aliased, you could type:

      $ \ls
      
  2. I like to have “.bash_history” in various project directories. Much like how git searches for the “.git” directory, I have an alias called “to” which does what “cd” does, but in addition, writes out the history for the old directory, changes HISTFILE, clears history, then locates and reads in the histfile for the new directory.

    When working on multiple unrelated projects simultaneously, and switching between them, it becomes much easier to find the commands you want.

  3. For me the most important use of the history file is just to look up commands I have used sometime before and now have forgotten the syntax to or the options given to it. I see the option to prevent addition of duplicates to the history file but is there also a way that the same command(s) applied to different files also do not get stored? I am assuming that the ignore-duplicate option will fail since the filenames of the files the command is operating on are different.

    • There’s probably not a built-in way to do this, but you could always use post-processing in a PROMPTCOMMAND or .bash_logout file to filter the text with awk to remove such duplicates.

  4. HISTTIMEFORMAT=’%F %T ‘ does not store the timestamps – they are stored in the histfile automatically, this just formats them in some human readable format – (per default its set to ”, so no time is displayed at all)

  5. Pingback: Control your history (bash) « 0ddn1x: tricks with *nix

  6. Pingback: Bash: Mejorando el historial de comandos | Attack and Release!

  7. Pingback: S06E43 – It’s a Wonderful Ubuntu | Ubuntu Podcast

  8. Pingback: Ubuntu Podcast from the UK LoCo: S06E43 – It’s a Wonderful Ubuntu | itux.info

  9. Pingback: BASH history articles - Best Bash History Settings (at top) | kossboss

  10. You gave some good suggestions for HISTIGNORE, but since everyone has different habits, I’d suggest this to show the top candidates:

    cat ~/.bash_history* | sort | uniq –count | sort -n | tail

    • It seems to me there’s another purpose to which the output of

      cat ~/.bash_history* | sort | uniq -c | sort -n | tail

      can be put. John F’s suggestion was to use the output to identify candidates for inclusion in the HISTIGNORE line of the .bashrc file, as a function of the initial state of the .bash_history file.

      I took some of the suggestions here and added the following to my .bashrc:

      HISTCONTROL=ignoreboth:erasedups HISTIGNORE=’ls:clear:bg:fg:history:exit:pwd:cd\ ..:ls\ *:history\ *’ HISTTIMEFORMAT=’%F %T ‘ PROMPT_COMMAND=’history -a’ HISTFILESIZE=100000 HISTSIZE=100000

      I had previously eliminated the more mundane commands in .bashhistory manually (e.g. cd, exit, clear, pwd, etc.), so the command mentioned wasn’t used to identify cruft. I then mv-ed the .bashhistory file out of the way, appending some notation to the filename, and exited the session, creating a new, empty .bashhistory file. I then populated the new .bashhistory file with a selection of the most-frequently-used items in the history, found in the output of the command above*, editing the output to remove line-initial counts, and so on. Exiting the session once more and starting a new one, I was left with a preened and edited selection as a starting point for the history and some desired–and long-sought–changes to bash’s behaviour in maintaining its history.

      • Note the asterisk.
  11. A fun problem occurs if you use TAB command completion and the shell finds a unique match.

    If I type hisTAB this expands to history _ (where _ is the cursor). I.e. there’s a space at the end of the line, and “history ” (with a space) isn’t matched by :history: (without a space).

    So, I have

    HISTIGNORE=’bg:fg:history\ *:ls:ll:la’

Leave a Reply

Your email address will not be published. Required fields are marked *

You can use Markdown if you want.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>