2022-03-03
This is the first in a series of posts about Bash history configuration.
Bash can keep a history of the commands you’ve issued and make them available via multiple methods, including Readline history commands and history expansion.
An example of a Readline history command is reverse-search-history
,
which is usually bound to C-r
(Ctrl+R), and incrementally searches the history
backwards.
An example for history expansion is !!
, an event
designator for the previous command.
Having your history around is very useful, but the default settings leave a few things on the table:
ls
,
which you’re not very likely ever to feel like retrievingIn these posts, I explain my Bash history setup, which addresses all of these points. “Perfect” is of course in jest—I don’t think I’ve seen many topics where people are as opinionated as when it comes to customizing a command-line setup. So, “perfect for me”, probably.
Note that I’m not going to talk about settings that change the behaviour of history expansion, but only how history is stored.
Bash can be compiled without history support
(--enable-history
option for configure
), but
it’s enabled by default unless not supported by the operating
system.
Given history support, interactive shells have history turned on by
default, but this can also be controlled using the history
shell option:
set -o history
to enable, and
set +o history
to disable. If enabled, the SHELLOPTS
variable contains history
, and the status is also reported
by set -o
.
The first nice-to-have is history that goes back all the way.
To understand how this works, we have to know a bit about how Bash stores history. Command history is stored in multiple places: each session has an in-memory history, which is initialized from a history file; when the session is finished, the in-memory history is written back to the history file.
Configuring this in a way so multiple parallel sessions don’t wipe out each other’s histories will be subject of a separate post; for now, we’re just thinking about a single session.
The history file by default lives at ~/.bash_history
; to
put it elsewhere, set the HISTFILE
variable. I like my home directory uncluttered, and I try to follow the
XDG
Base Directory Specification, so I have this in my
.bashrc
:
HISTFILE="$HOME/.local/share/bash/history"
where ~/.local/share
is the default value of
$XDG_DATA_HOME
.
When the session history gets written to the history file, the file
is either overwritten, or the history is appended. This is controlled
with the histappend
shell option:
shopt -s histappend
to append, and
shopt -u histappend
to overwrite the history file.
Since we only care about an individual shell session so far, we don’t need to append; we can overwrite the history file at the end of each session without losing anything.
The size of the history is controlled with the HISTSIZE
variable (defaults to 500), and the size of the history file with HISTFILESIZE
.
Common advice is to just set these to large numbers; however, since Bash
4.3, they can be set to a negative value for unlimited history. (Watch
out, setting to 0 disables history and truncates the history file,
respectively!)
So, for an infinite history (and so far ignoring implications of
parallel shell session), we’d want something like this in our
.bashrc
:
# No clutter in the home directory
HISTFILE="$HOME/.local/share/bash/history"
# Overwrite when storing
shopt -u histappend
# Infinite session history
HISTSIZE=-1
# Infinite history file
HISTFILESIZE=-1
In the next post, we’ll look at controlling what exactly goes into the history.