Authors Top

If you have a few years of experience in the Linux ecosystem, and you’re interested in sharing that experience with the community, have a look at our Contribution Guidelines.

1. Overview

Whenever we work on any Linux terminal, more often than not, we use the Bash shell. We type many common commands multiple times with different options. Sometimes while typing a verbose command, we realize that there is some mistake. Instead of retyping the whole text, we use rich history features to correct and search.

In this tutorial, we’ll see how to use Bash history to work more efficiently.

2. Basic Configuration to Enable History

For the Bash shell to allow the history operation, we first need to enable history. We also need to configure the Readline library to read the input from the command line. In this section, we’ll discuss how to enable history and configure the Readline library.

When the Bash shell starts, it initializes history and reads the .inputrc file for the Readline library configuration.

2.1. Enabling Bash History

First, let’s check if history is enabled or not:

$ set -o | grep history
history        	on

In case history is turned off, we’ll turn it on by setting in the .bashrc file:

$ set -o history

After that, let’s find out whether the file location and history size are set or not by using the echo command. The HISTFILE variable stores the location of the history file:

$ echo $HISTFILE

If the value is /dev/null, then as always, we need to set it up in our .bashrc file:

HISTFILE=$HOME/.bash_history

We use the HISTSIZE and HISTFILESIZE variables to configure the length of the Bash history:

$ echo $HISTSIZE
$ echo $HISTFILESIZE

If the value of either HISTSIZE or HISTFILESIZE is zero, we need to configure them in the .bashrc file:

HISTFILESIZE=500
HISTSIZE=500

2.2. Configuring the Readline Library

Now, we’ll configure the Readline Library. For this purpose, we need to work with the .inputrc file. The .inputrc file describes key bindings, variable assignment, and conditional syntax. We can override the default behavior of the Readline library by customizing the .inputrc file in the home directory.

For changing the editor from emacs (default mode) to vi:

$ set editing-mode vi

To set the visible bell:

$ set bell-style visible

In case we want to ignore the case:

$ set completion-ignore-case On

After setting the variables, let’s move on to configuring keys for traversal.

For ANSI mode, we’ll set arrow keys as:

"\M-[D":        backward-char
"\M-[C":        forward-char
"\M-[A":        previous-history
"\M-[B":        next-history

We can get the same behavior by using the bind command in the .bashrc file:

$ bind '"\e[A": history-search-backward'
$ bind '"\e[B": history-search-forward'

Here, \M- is the meta key. If the meta key is not there, it implies the escape key, which is \e.

3. Using Bash History

Now that the shell is configured, let’s start using the history. First, we’ll see how to search the existing history file. Then, we’ll learn how to use the built-in commands that Bash provides. And, in the end, we’ll see how to modify and execute the commands.

3.1. Traversing the History

We use arrow keys or Control keys to traverse the history:

  • ⬆️ or CTRL-p: Traverses backward
  • ⬇️ or CTRL-n: Traverses forward

3.2. Searching the Commands in History

We can search command history in either incremental or non-incremental mode. For incremental mode, the search begins as soon as we start typing the search string:

  • CTRL- r: searches in the backward direction
  • CTRL- s: searches in the forward direction

3.3. Bash Built-in Commands

The Bash shell comes with the built-in fc and history commands.

We use the fc command mainly to list, edit, and re-execute a portion of the history list, and we use the history command to manipulate the history list.

First, let’s look at the fc command.

To list the commands used on the terminal:

$ fc -l
39	 vi file1
40	 ls -la file3
41	 ls file3
42	 cd ..
43	 history
44	 ls -la file3
45	 ls
46	 cd -
47	 ls
48	 rm file*
49	 touch file1 file2 file3 file4
50	 ls file3
51	 history 

As we can see, we got the listing of history commands.

In case we want to edit the commands before executing, we use fc with different options. All the fc commands below open in an editor. 

In case the last command is:

$ cat incorrectfilename.demo

Then, after executing the command:

$ fc

The editor will contain command or text:

$ cat incorrectfilename.demo

And, to edit the command at the nth location, say 4th from the end of the listing below:

$ fc -4
   43  history
   44  ls -la file3
   45  ls
   46  cd -
   47  ls
   48  rm file*
   49  touch file1 file2 file3 file4
   50  ls file3
   51  history 
   52  tou
   53  fc -l
   54  ls file3

In this case, the editor will contain the command or text:

$ history

To edit commands in a range, we use:

$ fc 49 50

The editor will open with the following lines:

$ touch file1 file2 file3 file4
$ ls file3

If needed, we can change commands in the editor. After exiting the editor, the modified command is executed.

Now, let’s take a look at the history command.

This command lists all the executed commands from the history file along with line numbers:

$ history
   33  ls
   34  ls
   35  pwd
   36  pwd
   37  set -o history
   39  pwd

In case we want to see the last n executed commands:

$ history 3
   38  set -o history
   39  pwd
   40  history 3

We can execute the last command by using:

  • ⬆️
  • !!
  • !-1
  • CTRL-P

To clear the history:

$ history -c

As expected, if we execute the history command now, only one command is listed.

$ history
   32  history

To delete a specific command from the history:

$ history -d 32

It will delete event number 32 from the history file.

3.4. Using Simple History Expansion

Other than built-in commands, history has a rich set of features. We use the expansion character ‘!’ on the lines/commands in history. Over here, the command selected from the history is called an event, and words are the part of the event on which we act. We also apply modifiers to manipulate the selected words.

In case we want to execute an event, say the command at line 34 from the history:

!34

To run an event starting from specific letters, say last used command starting from p:

!p
$ pwd

3.5. More Advanced History Commands

Sometimes, we want to execute a different command but using the same value or parameter. We’ll use the word designator “!!:$” for this purpose.

As we can see below, the cd command takes the argument Demo from the last event, ‘ls Demo’:

$ ls Demo
file1		file2
$ cd !!:$
$ cd Demo

If we want to apply the arguments of the last event on the current command, then we use the expansion character ‘!’ followed by ‘^’, ‘$’, or “:n”.

Here, rm takes the first argument of event touch and removes file1. However, to remove file4, we’ll use the character ‘$’. Similarly, we’ll use “:2” to remove file2:

$ touch file1 file2 file3 file4
$ rm !^
$ rm file1

Another way we can manipulate an event is by using modifiers. Here, “!to:3” expands to the last event starting with the text “to”, which is the touch command in this case. After that, it substitutes the 3rd argument of the event as an argument for the ls command:

touch file1 file2 file3 file4
$ ls !to:3
$ ls file3
file3

3.6. Showing the Date and Time of Each Command in History

By default, most Linux distributions don’t show the date and time when each command was executed. We can modify this behavior by setting the HISTTIMEFORMAT variable either temporarily or permanently.

Let’s first see how we can set it temporarily:

$ export HISTTIMEFORMAT='%Y-%m-%d %H:%M:%S '

We’re exporting the HISTTIMEFORMAT variable and setting it to the standard date-time format.

%Y-%m-%d represents the date format starting with the year, month, and then, day. %H:%M:%S represents the hour, minute, and secondThis method is very useful because it gives us more control of what to display.

We can simplify this format by modifying the command:

$ export HISTTIMEFORMAT='%F %T '

Here, %F expands to the standard date format, and %T expands to the standard time format.

Let’s now run the history command:

$ history
   33 2022-05-03 17:58:33 ls
   34 2022-05-04 12:04:44 ls
   35 2022-05-04 12:04:57 pwd
   36 2022-05-04 12:05:44 export HISTTIMEFORMAT='%F %T '
   37 2022-05-04 12:05:44 history

We can see that each command is preceded by the date and time it was executed.

Now, let’s see how we can set the HISTTIMEFORMAT variable permanently.

We first need to open the ~/.bashrc file:

$ nano ~/.bashrc

Then, we add this line:

export HISTTIMEFORMAT='%F %T '

Finally, we need to run the source command to update the change we made:

$ source ~/.bashrc

Now, every time we run the history command we’ll also get the date and time that each command was executed.

4. Conclusion

In this article, we discussed how the Readline and the History libraries help in Bash history expansions. We also saw how using these expansions can increase our work efficiency. We can always refer to the following references for more details:

  1. Readline Library
  2. History Expansion
  3. Sample inputrc file
Authors Bottom

If you have a few years of experience in the Linux ecosystem, and you’re interested in sharing that experience with the community, have a look at our Contribution Guidelines.

Comments are closed on this article!