11

I am happy and really like the Ctrl-R backward search feature of the bash shell. Some of my colleagues don't like it, since it is sometimes confusing. I understand them. If you enter the wrong characters, the current position in the history is somewhere in the past, and you won't find the recent matches.

Is there a more user friendly alternative for seaching backward in the shell history?

I want to stick with bash. Suggesting an alternative shell is not an answer to this question.

The issue with the "lost position" is explained here: Reset bash history search position. These solutions work. That's right. But the solution there are not easy and user friendly according to my point of view. These solutions are not simple and straight forward. These are solutions of the past. In the past the human needed to learn the way the computer wanted the input. But today the tools should accept the input in a way which is easy for the user.

Maybe someone knows a IDE of jetbrains like PyCharm. If you search for "foobar" you even get the lines which contain "foo_bar". That's great, that's unix :-)

4
  • I don't care about the bounty or about your accepting my answer, but maybe you care to ellaborate why changing the search direction with ^S does not fix your "lost position" issue (a ^S after ^R and vice-versa will change direction from the current position, not from the start/end). Otherwise, pycharm, jetbrainz, past & present and other pretentiousness, let's better not go further into that.
    – user313992
    Commented Jun 11, 2019 at 7:02
  • I can use and live with ^S. But usability is different. Usability would be better if you just need to remember one magic key stroke. My girlfriend understands backward search with ctrl-r. But if she makes a typo, she is lost. I want to improve this. I want it to be a no-brainer.
    – guettli
    Commented Jun 11, 2019 at 9:11
  • So, it sounds like what you want is Ctrl-R to wrap its searches. Is that the kind of usability you have in mind? Not sure if that exists, though.
    – Randall
    Commented Jun 14, 2019 at 21:28
  • I sent a bug report (updated link). Commented Nov 11, 2020 at 12:48

5 Answers 5

5
+50

I'm using the fuzzy finder program FZF. I've written my own key bindings and shell scripts to utilize FZF as my tool of choice to reverse-search an interactive Bash shell's history. Feel free to copy and paste the code from my Config GitHub repository.

~/.bashrc configuration file

# Test if fuzzy finder program _Fzf_ is installed.
#
if type -p fzf &> /dev/null; then

  # Test if _Fzf_ specific _Readline_ file is readable.
  #
  if [[ -f ~/.inputrc.fzf && -r ~/.inputrc.fzf ]]; then

    # Make _Fzf_ available through _Readline_ key bindings.
    #
    bind -f ~/.inputrc.fzf
  fi
fi

~/.inputrc.fzf configuration file ##

$if mode=vi

  # Key bindings for _Vi_ _Insert_ mode
  # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  set keymap vi-insert

  "\C-x\C-a": vi-movement-mode
  "\C-x\C-e": shell-expand-line
  "\C-x\C-r": redraw-current-line
  "\C-x^": history-expand-line
  "\C-r": "\C-x\C-addi$(HISTTIMEFORMAT= history | fzf-history)\C-x\C-e\C-x\C-r\C-x^\C-x\C-a$a"

  # Key bindings for _Vi_ _Command_ mode
  # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  set keymap vi-command

  "\C-r": "i\C-r"
  "\ec": "i\ec"

$endif

fzf-history executable Bash script

#!/usr/bin/env bash
#
# Retrieve command from history with fuzzy finder
# ===============================================
# Tim Friske <[email protected]>
#
# See also:
#   * man:bash[1]
#   * man:fzf[1]
#   * man:cat[1]

shopt -os nounset pipefail errexit errtrace
shopt -s extglob globstar

function print_help {
  1>&2 cat \
<<'HELP'
usage:
  HISTTIMEFORMAT= history | fzf-history
HELP
}

function fzf_history {
  if [[ -t 0 ]]; then
    print_help
    exit
  fi

  local fzf_options=()
  fzf_options+=(${FZF_DEFAULT_OPTS:-})
  fzf_options+=('--tac' '-n2..,..' '--tiebreak=index')
  fzf_options+=(${FZF_HISTORY_FZF_OPTS:-})
  fzf_options+=('--print0')

  local cmd='' cmds=()
  while read -r -d '' cmd; do
    cmds+=("${cmd/#+([[:digit:]])+([[:space:]])/}")
  done < <(fzf "${fzf_options[@]}")
  if [[ "${#cmds[*]}" -gt 0 ]]; then
    (IFS=';'; printf '%s\n' "${cmds[*]}")
  fi
}

fzf_history "$@"

key-bindings.bash sourceable Bash script

Taken and slightly adapted from FZF's Bash key bindings file here are the Emacs mode compatible key bindings for Bash's history reverse-search with Ctrl-R (untested):

if [[ ! -o vi ]]; then
  # Required to refresh the prompt after fzf
  bind '"\er": redraw-current-line'
  bind '"\e^": history-expand-line'

  # CTRL-R - Paste the selected command from history into the command line
  bind '"\C-r": " \C-e\C-u\C-y\ey\C-u$(HISTTIMEFORMAT= history | fzf-history)\e\C-e\er\e^"'
fi
3
  • This works only in vi mode, is there an option for emacs mode (default)?
    – user232326
    Commented Jun 7, 2019 at 19:52
  • I just didn't bother to set up key bindings in Emacs mode because I prefer Vi mode. But I guess you can figure out that yourself from Bash Readline's manpage. The only thing you should need to adapt are the key bindings in the ~/.inputrc.fzf file
    – Tim Friske
    Commented Jun 7, 2019 at 19:57
  • I just added the section key-bindings.bash sourceable Bash script with Emacs mode key bindings that should hopefully work.
    – Tim Friske
    Commented Jun 7, 2019 at 20:19
4
  • Up arrow: only practical for very recent stuff.
  • grep blablabla ~/.bash_history: you will have to set bash to save history to file after each command.

From my ~/.bashrc You may want to find out what the commands do and tweak.

# don't put duplicate lines in the history. See bash(1) for more options
HISTCONTROL=ignorespace:ignoredups:erasedups
HISTFILESIZE=99999
HISTSIZE=99999
export PROMPT_COMMAND="history -a; $PROMPT_COMMAND"
# append to the history file, don't overwrite it
shopt -s histappend
#history
shopt -s cmdhist
shopt -s histreedit
shopt -s histverify
shopt -s lithist
3
  • With "search" I mean "typing something"... like a search engine.
    – guettli
    Commented Jun 7, 2019 at 15:27
  • Don't you need to read the history file as well, with history -r after history -a?
    – Gauthier
    Commented Feb 10, 2021 at 6:57
  • Maybe. You don't have to. It depends what you want. Commented Feb 10, 2021 at 7:10
4

McFly is another option. It's very easy to install - you can do it through brew or just download the latest binary. It's written in Rust so they're statically linked. No dependency nonsense.

Then just add this to your .bashrc/.zshrc:

eval "$(mcfly init bash)" # or zsh

It gives you a full-screen UI sorted in some intelligent way.

enter image description here

1

For what it's worth, if you disable the stop/start feature of your tty (that you probably don't use that much), you can change the search direction by pressing Control-S.

% stty stop undef

% true str1
% true str2
% true str3
% true str4
Control-R => (reverse-i-search)`str': true str4
Control-R => (reverse-i-search)`str': true str3
Control-S => (i-search)`str': true str3
Control-S => (i-search)`str': true str4

As to those keybindings not being "user-friendly" or intuitive, they're emacs keybindings. emacs is not for everybody, there's no surprise there (though I know secretaries and other not-so-pretentious individuals which were able to master them in no time and without much fuss). It's more of a culture thing.

1
  • 1
    It might be useful to show a typo that gets you lost in the middle of history, e.g. ste. You correct the typo with Backspace r. (Emacs at this point would automatically correct the history position, but Bash won’t do that.) You manually change the search direction with Ctrl-S and plough ahead through the matches. — It’s the best workaround I found (+1), but still unsatisfactory. While it corrects the search direction, it fails to correct the search position which remains a problem. Commented Nov 10, 2020 at 6:05
0

FZF comes with support for bash (also zsh & fish).

@Tim Freske's answer describes their modifications for vi style keybinding.

Default key bindings are emacs style. Which even overrides the Ctrl-r behavior to fuzzy find without losing position. They may not be enabled by default. To enable them add this to .bashrc:

source /usr/share/doc/fzf/examples/key-bindings.bash

(If this doesn't work, do apt-cache show fzf and find ...fzf/README... file, it lists commands for bash, zsh, fish and vim)

1
  • Tim already mentioned what you're explaining here.
    – annahri
    Commented May 26, 2021 at 8:28

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .