7

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?

  • This question may be better suited for the Vi and Vim Stack Exchange Site. – Paradox Jun 29 '16 at 19:01
  • 3
    @Paradox, but it is not really a vi question, is it? – René Nyffenegger Jun 29 '16 at 19:02
  • That's how it appears to me, but I could be mistaken since it involves BASH as well. – Paradox Jun 29 '16 at 19:04
  • 3
    I don't have any more supporting evidence, but this page mentions that "the Readline library does not have a full set of vi editing functions, it does contain enough to allow simple editing of the line" – Jeff Schaller Jun 29 '16 at 19:16
  • 1
    I usually search it by piping history command's output through grep to get a number for the historic command I was looking for. But that wouldn't answer the question – infixed Jun 29 '16 at 20:46
  • 2
    This is *not* a vi question; this is a bash question. It’s possible that the users of Vi and Vim Stack Exchange will be able to answer it easily, but it is more on-topic here. Since the OP posted it here, it should stay here. If it doesn’t have a satisfactory answer after about 48 hours, then maybe we should consider migrating it. – G-Man Says 'Reinstate Monica' Jun 30 '16 at 06:00
  • @René Nyffenegger: I’m not sure what Anthony Geoghegan is trying to say in his answer. I interpret it to mean that bash’s vi mode doesn’t support regular expressions, but rather the shell pattern matching syntax (i.e., what you use for pathname expansion (i.e., globs/wildcards) and in case statements). If that’s the case, you should be able to search for lines containing foo followed by zero or more of any character followed by bar — by typing /foo*bar. But I can’t get that to work either. – G-Man Says 'Reinstate Monica' Jun 30 '16 at 06:00

1 Answers1

9

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).

  • 1
    I filed a bug report for this, fwiw: http://lists.gnu.org/archive/html/bug-readline/2016-08/msg00005.html So.. maybe some year soon (: – jwd Apr 26 '18 at 17:00
  • I just stumbled upon my own question... and it is working in bash 5.0.16 (and probably in earlier versions, too) – René Nyffenegger Mar 27 '20 at 19:57
  • @jwd Thanks to your bug report and all the great work of the Bash maintainer and developers, this feature has been implemented for more than a year. :) – Anthony Geoghegan Mar 28 '20 at 00:50