Bash – How to Search Bash’s History in Vi Mode for ‘foo.*bar’

bashcommand historyreadlineregular expression

I have my bash environment in vi mode (set -o vi). So I can type <ESC>/ followed by a word, followed by enter, and bash searches for the word in the history.
Since / is also vi's method to search for regular expressions, I was under the expression that bash will search for regular expressions as well.

Unfortunately, when I type <ESC>/foo.*bar in bash, it does not find any line in the history that matches the regular expression foo.*bar.

Am I overlooking something or is it just not possible to search the history for regular expressions?

Best Answer

The short answer is that you can not use regular expressions to search the shell history. According to POSIX (the standard for Unix-like operating systems), you should be able to search using regular shell pattern matching (as used for filename globbing and with case statements). This feature is referred to as non-incremental search but it currently does not seem to be correctly implemented in Bash.

POSIX specification

The POSIX specification for shell Command Line Editing (vi-mode) states that these search patterns should use regular shell pattern matching. While the ^ meta-character is used to match the start of a line, they are not regular expressions.

/pattern<newline>

Move backwards through the command history, searching for the specified pattern, beginning with the previous command line. Patterns use the pattern matching notation described in Pattern Matching Notation , except that the '^' character shall have special meaning when it appears as the first character of pattern. In this case, the '^' is discarded and the characters after the '^' shall be matched only at the beginning of a line. Commands in the command history shall be treated as strings, not as filenames.

Documented Bash implementation

Bash uses the GNU Readline library to provide its interactive line-editing and history searching capabilities. The official documentation for the Readline library focuses more on Emacs mode, but a short section in its manual, Readline vi Mode states that

While the Readline library does not have a full set of vi editing functions, it does contain enough to allow simple editing of the line.

The Readline vi mode behaves as specified in the POSIX standard.

Actual Bash implementation

After a number of experiments on two different systems, I found that the non-incremental searching in Bash/Readline does not work as described in its official documentation. I found that the * was treated as a literal asterisk rather than a pattern that matches multiple characters. Likewise, the ? and [ are also treated as literal characters.

For comparison, I tried using Vi-mode in tcsh and verified that it correctly implements history searching as specified in the POSIX standard.

I then downloaded and searched through the code for the Readline library and found its history searching functions use a simple substring search and don’t use any search pattern meta-characters – aside from the caret, ^ (see search.c from the git repository for the Readline library).

I presume the Bash/Readline developers have yet to implement this feature. I couldn’t find a bug-list but the CHANGES files shows that they’ve been regularly fixing issues relating to Vi-mode.

Update: This feature was implemented in Readline 8.0 (released with Bash 5.0 in January 2019). As documented in its CHANGES:

New Features in Readline

a. Non-incremental vi-mode search (N, n) can search for a shell pattern, as Posix specifies (uses fnmatch(3) if available).