1. Overview

When working in the terminal, we’re bound to execute commands and repeat them multiple times. Thus, we may take advantage of the Tab autocompleting feature or simply use the Up arrow key to look at the commands we used. However, these methods might not be efficient when working with a long command history.

In this tutorial, we’ll learn how to interactively search the Zsh history from the latest to the oldest command entries.

2. In Emacs Mode

If we’re using the Emacs input mode in Zsh, then doing a reverse history search is as easy as holding down Ctrl and pressing R. If that shortcut fails for some reason, it could be that our current keymap or key notation isn’t set for Emacs.

2.1. Setting the Emacs Keymap

To ensure that Zsh interprets our key combinations in the Emacs style, we should explicitly select the appropriate keymap:

% bindkey -e

The bindkey command uses the -e option (short for emacs) to set the emacs keymap as the default for our Zsh session. This means we gain access to the same default command hotkeys similar to those used in Bash.

2.2. Searching the Zsh History

Each keymap contains a set of keys assigned to specific functions or widgets. So, to find out which ones can start a reverse history search, let’s run the bindkey command on its own. This way, we list the current predefined key bindings:

% bindkey
...
"^R" history-incremental-search-backward
"^S"-"^T" self-insert
"^U" vi-kill-line
"^V" vi-quoted-insert
"^W" vi-backward-kill-word
...

We can notice in the output that the ^R or Ctrl+R is bound to history-incremental-search-backward, which is the widget responsible for the reverse search.

So, we can simply use the Ctrl+R hotkey to summon the reverse search prompt:

searching the zsh hidtory backward

As we type our search string, the shell shows us the most recent matched command. If we don’t get an exact match, we can hit Ctrl+R again to get the next matching command. We can repeat this multiple times, similar to how we’d press the Up arrow key to retrieve the previously executed command.

3. In Vi Mode

In vi mode, the Ctrl+R might not trigger a reverse search by default as the mode comes with its own unique key bindings.

3.1. Setting the Vi Keymap

While in vi mode, let’s set our keymap to the vi style key bindings:

% bindkey -v

The -v option above instructs our shell to interpret key commands in vi style. This directs it to use two different keymaps:

  • Insert mode uses the viins keymap
  • Command mode uses the vicmd keymap

This means each mode has its own specific set of widgets.

3.2. Identifying the Appropriate Key Binding

In contrast to the emacs keymap, the vi mode relies on the vi-history-search-backward widget to search the Zsh history backward.

Let’s confirm this by listing the key bindings relevant to the Command mode:

% bindkey -M vicmd
...
"/" vi-history-search-backward
"0" vi-digit-or-beginning-of-line
"1"-"9" digit-argument
":" execute-named-cmd
"n" vi-repeat-search
...

The above command uses the -M switch to list the available key bindings used by the vicmd keymap. We can notice from the output that the vi-history-search-backward is bound to the / (forward slash) character.

3.3. Searching the History

There are several steps to search the Zsh history:

  1. Press the Esc key to enter Command mode
  2. Type / followed by the string we want to search for
  3. Hit Return to execute

In case the first hit didn’t work for us, we can simply continue scrolling backward through the matched commands by clicking the n key.

3.4. Creating a Custom Key Binding

While the vi mode has its own way of searching the command history, it might be considered less efficient when compared to the Emacs way. Luckily, we can create our own key bind to invoke the history-incremental-search-backward even while in vi mode.

Let’s assign the Ctrl+R key combination to search the Zsh history in reverse, emacs style:

% bindkey '^R' history-incremental-search-backward

In the above command, the ^ caret character represents the Ctrl key, while R denotes its own key. Therefore, the bindkey command binds the Ctrl+R key sequence to the history-incremental-search-backward widget.

The command also adds this key binding to the viins keymap, so we should be in the Insert mode to trigger a reverse search using Ctrl+R.

4. Conclusion

In this article, we discussed the process of reverse-searching the Zsh history in both emacs and vi modes. We also saw how to bind and use the history-incremental-search-backward widget specifically in vi mode.

In conclusion, the choice of which method to use in searching the Zsh history simply comes down to personal comfort and familiarity.