3

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: https://stackoverflow.com/questions/34793704/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 :-)

  • 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. – pizdelect Jun 11 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 Jun 11 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 Jun 14 at 21:28
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 <me@tifr.de>
#
# 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
  • This works only in vi mode, is there an option for emacs mode (default)? – Isaac Jun 7 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 Jun 7 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 Jun 7 at 20:19
  • Thank you!. Testing. – Isaac Jun 7 at 20:23
2
  • 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
  • With "search" I mean "typing something"... like a search engine. – guettli Jun 7 at 15:27
0

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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.