BASH (Bourne Again SHell) is the default shell in practically all Linux-based operating systems. All the commands we write in the terminal are interpreted by the shell, and become part of its history. In this tutorial we see where the shell history is saved, and how to manage it using the “history” built-in command and some environment variables.
In this tutorial you will learn:
- Where and how BASH history is saved
- How to visualize the current shell history
- How to clean the Bash shell history
- How to force shell history to be written to history file
- How to modify history behavior via environment variables
Software requirements and conventions used
|Category||Requirements, Conventions or Software Version Used|
|Software||The Bash shell|
|Conventions||# – requires given linux-commands to be executed with root privileges either directly as a root user or by use of
$ – requires given linux-commands to be executed as a regular non-privileged user
Where is BASH history kept?
If we open a terminal emulator or we are working in a TTY, and we want to recall a command we run in the past, we usually press the upper arrow key to navigate back, or the down arrow key to navigate forward in the shell history. Have you ever wonder where and how Bash history is saved? The list of commands we invoke in the Bash shell are stored in the so called “history file”, which by default is
Commands are stored one per line in the file, however, they are initially kept in memory, and written to it only when the shell session is closed, or when we force the writing manually (we will see how to perform such action later in this tutorial).
Working with the “history” built-in command
To visualize the current content of the shell history, we can use the
historycommand, without passing any argument or option. Each line in the output produced by it, is prefixed by number:
$ history 1 echo "linuxconfig.org" 2 cat /etc/hostname 3 ls -l /etc/hostname 4 history
Cleaning the Bash shell history
history command is not only used to display the current shell history, but also to perform other operations. To clean all the current history of the Bash shell, for example, all we have to do is to invoke the it with the
We also have the chance to delete a specific command in the history, by using the
-d option, and passing the line offset as argument. Imagine we want to remove line
1 from the current in-memory history. We would invoke the
history command as follows:
$ history -d 1
Negative numbers can be used as offset: if we do so, the lines count will start from the end of the list. Passing
-1 as offset to the
-d option, for example, will cause the last line of the history to be removed. When we perform such operation, however, one thing must be taken into account: the removal will take place after the
history -d command is appended to the list itself, so to delete the third line from the end of the history we should actually run
history -d -4. As an alternative, we could change our configuration in order to make some commands like
history not to be included in the list. We can do so by working with the
HISTIGNORE variables: we will see how to do it in the curse of the tutorial.
Writing history to file manually
As we already mentioned, the history of the shell we are currently working in, is written to the history file only when the shell session is closed. What if we want to force in-memory history to be written at a specific time? Once again we can use the
history command to perform such action. This time we must invoke it with the
-w option, which takes no argument:
$ history -w
Modifying history behavior via environment variables
The behavior of the shell history can be modified by setting the value of some environment variables. Let’s see some examples.
The HISTCONTROL variable
In the previous section we briefly mentioned the
HISTCONTROL variable when we talked about excluding certain commands from being included in the shell history. This variable takes a colon-separated “list” of values which influence how commands are included in the history. On most distribution, its default value is simply
$ echo $HISTCONTROL ignoredups
What does it mean? The
ignoredups value makes so that a command is not recorded in the shell history if the previous command in the list is identical to it, so to avoid adjacent duplicates. If we want to avoid duplicates in the whole shell history no matter the position they have, we can use the
erasedups value, instead.
Another frequently used value for this variable, is
ignorespace, which makes so that commands preceded by a space are not included in the shell history. Let’s update the value of the variable on the fly, and verify this works:
$ HISTCONTROL="ignoredups:ignorespace" $ echo "this command will not be included in the history" "this command will not be included in the history" $ history 1 HISTCONTROL="ignoredups:ignorespace"
First we changed the value of the
HISTCONTROL variable from “ignoredups” to “ignoredups:ignorespace”, in order to use both values (we could simply have used
ignoreboth as a shortcut). After changing the variable value, we ran two commands, both preceded by a space. The last one,
history, showed the history content. As you can see by taking a look at the output of the command, only the variable assignment was included in the shell history, since the other two were preceded by a space.
Needless to say, the value assigned to the
HISTCONTROL variable the way we did above, will be kept only in the current shell session. To make it permanent we should include the assignemnt it in our shell environment file, then logout and login again (or source the file manually).
The HISTIGNORE variable
Just like the
HISTIGNORE accepts a colon-separated list of elements as value, but it is used to specify what commands should be excluded from the shell history. Let’s see an example: suppose we want to exclude the
ls and the
history commands from being included in the shell history. Here is the value we would assign to the
$ HISTIGNORE="ls:history" $ echo "this will be included in history" "this will be included in history" $ ls file.txt $ history 1 echo "this will be included in history"
As you can observe, after we changed the value assigned to the
HISTIGNOREvariable, we just echoed a message, then we run the
historycommands. From the output of the latter we can see that only the first command was included in the history. One thing should be noticed, however: only the exact command we specify in
HISTIGNOREwill be excluded. For example, above we set
lsto be excluded, however if we run
ls -l, the command will be included in the shell history:
$ HISTIGNORE="ls:history" $ echo "this will be included in history" "this will be included in history" $ ls -l -rw-rw-r--. 1 egdoc egdoc 0 Jan 7 11:51 file.txt $ history 1 echo "This ill be included in history" 2 ls -l
How to avoid this? We can simply use a
* (glob) as part of the specified command: it does match every character. We could modify the value of the
HISTIGNORE variable, in the following way:
$ HISTIGNORE="ls *:history" $ echo "this command will be included in history" this command will be included in history $ ls -l -rw-rw-r--. 1 egdoc egdoc 0 Jan 7 11:51 file.txt $ history 1 HISTIGNORE="ls *:history" 2 echo "This command will be included in the shell history"
The HISTSIZE variable
HISTSIZE variable controls how many commands are kept in the Bash history. By default, at least on the distribution I am using at the moment of writing (Fedora 35), it is set to
1000 by default:
$ echo $HISTSIZE 1000
We can increase or decrease this value and adjust it to our needs. If we exceed the specified value, older commands are deleted from the beginning of the list:
HISTSIZE=3 $ echo "first command" first command $ echo "second command" second command $ echo "third command" third command $ history 2 echo "first command" 3 echo "second command" 4 echo "third command"
As you can see from the lines offset the first command we ran, which was the variable assignment, is deleted from the history list once we run the fourth command. Only three commands are kept. This is an extreme example, but it does hopefully give you an idea.
The HISTTIMEFORMAT variable
HISTTIMEFORMATvariable can be used to prefix each command in the shell history with a timestamp. The timestamp format is determined by the value assigned to the
HISTTIMEFORMATvariable. Some of the notations that can be used are:
As always, let’s see an example. Let’s say we want each command in history be prefixed by the date it was launched in, using the
YYYY/MM/DD format. Here is the value we would assign to the variable:
$ HISTTIMEFORMAT="%Y/%m/%d %H:%M:%S " $ echo "this command will be prefixed by a timestamp in shell history" This command will be prefixed by a timestamp in shell history $ history 1 2022/01/07 17:12:09 HISTTIMEFORMAT="%Y/%m/%d %H:%M:%S " 2 2022/01/07 17:12:12 echo "this command will be prefixed by a timestamp in shell history
In this tutorial we briefly saw how commands we write when using Bash are remembered in the shell history. We saw that history is initially kept in memory, and then stored in the so called “history file”, once the shell session is closed. We saw how to visualize the current shell history, how to clean it, and how to force it to be written to file immediately with the “history” command. We also saw how to modify history behavior via some environment variables.