How can I search history with text already entered at the prompt in zsh?

In zsh, I know that I can search history with Ctrl+r. However, oftentimes I start to type a command directly at the prompt, but then realize I should be searching history. When I hit Ctrl+r, it brings up a blank history search prompt like this:

history search prompt not pre-filled

Notice how there is text at my prompt but not at the history search prompt. How do I start the history search with the text already in the prompt, so it looks like this:

history search prompt pre-filled

Asked By: Sean Mackesey

||

You can use zle’s history-search functionality:

bindkey "^[[A" history-beginning-search-backward
bindkey "^[[B" history-beginning-search-forward

This binds Up and Down (adjust for your own escape sequences) to a history search, backwards and forwards, based upon what has already been entered at the prompt.

So, if you were to enter “vim” and hit Up, zsh will traverse backwards through your history for only those commands commencing with “vim”.

You can additionally have the cursor placed at the end of the line once you have selected your desired command from zsh’s history by using the history-search-end function (typically located in /usr/share/zsh/functions/Zle/) and appending -end to the end of each line, like so:

autoload -U history-search-end
zle -N history-beginning-search-backward-end history-search-end
zle -N history-beginning-search-forward-end history-search-end
bindkey "^[[A" history-beginning-search-backward-end
bindkey "^[[B" history-beginning-search-forward-end
Answered By: jasonwryan

You might want to use the script at https://github.com/zsh-users/zsh-history-substring-search

Where you can type in any part of any previously entered command and press the Up and Down keys to cycle through the matching commands.

Answered By: number5

Another useful option is history | grep

Assign an alias, e.g.

alias hg='history | grep'

then you can type hg whatever to search for commands you’ve used, e.g.

$ hg chmod                                                                                                       
 1309  chmod +x rotate_files.sh 
 1385  chmod +x rotate_files_270.sh 
 1512  chmod +x testy.sh 
 1528  chmod +x act_on_2_numbers.sh 
 2142  chmod +x ~/bin/display_tmux_pane_pwd.sh
 4532  chmod +x cat_files.rb 

I put this alias in my dot files.

Answered By: Michael Durrant

If you are using oh-my-zsh, add history-substring-search to the plugins=(...) line.

Then add

bindkey "^[[A" history-substring-search-up
bindkey "^[[B" history-substring-search-down

somewhere below the line that read source $ZSH/oh-my-zsh.sh. Save and fire up a new terminal or run source ~/.zshrc in the current terminal.

Note: ^[[A is the escape sequence for up arrow in the terminal I use (kitty) and many others. To check in your terminal of choice, type in showkey -a and then press they key you want to find the escape sequence for.

Answered By: joelostblom

Third part solutions

1 – What about using zsh-autosuggestions?

The thing is, for each command you type this plugin will show you some suggestions that could be accepted or not. Try it out and give us some feedback.

2 – The fzf after installed and properly configurated add an widget that changes your reversed search history (by default binded to fzf-history-widget Ctrlr), it adds some fuzzy search on your command history. I am using it and combined with the autosuggestions works like a charm.

Native solution

With no plugins we can press Ctrlr to perform a reverse seach on the history, as soon as you start typing the matched commands will appear as suggestions.

Answered By: SergioAraujo

I agree with cheflo that “substring” search is more useful. I cannot comment there so I started a new answer. I use oh-my-zsh, and add “history-substring-search” to the plugins=(…) of ~/.zshrc. Then source ~/.zshrc. Do not need to add anything more. Use “bindkey” to verify:

"^[OA" history-substring-search-up
"^[OB" history-substring-search-down

Later, you type “to” and up arrow, “history” will appear and “to” highlighted (if you used “history” command before).

Answered By: James

You could instead use zaw, which completely replaces your search with a much better multi keyword super search, and fixes your problem as well – searching history is only one of the things zaw can search.

Small intro/discussion here

Answered By: Brad Parks

I’d highly recommend using "$terminfo[kcuu1]" or "$key[Up]" rather than hard-coded stuff like "^[[A" which may or may not work on any particular system.

Check out /etc/zsh/zshrc for more keys. Here’s what it looks like on my system. I think the terminfo keys are more likely to be defined.

key=(
    BackSpace  "${terminfo[kbs]}"
    Home       "${terminfo[khome]}"
    End        "${terminfo[kend]}"
    Insert     "${terminfo[kich1]}"
    Delete     "${terminfo[kdch1]}"
    Up         "${terminfo[kcuu1]}"
    Down       "${terminfo[kcud1]}"
    Left       "${terminfo[kcub1]}"
    Right      "${terminfo[kcuf1]}"
    PageUp     "${terminfo[kpp]}"
    PageDown   "${terminfo[knp]}"
)
Answered By: zzxyz

I use the vi-mode plugin. And then in my ~/.zshrc I have the following bindings:

bindkey "^P" history-beginning-search-backward
bindkey "^N" history-beginning-search-forward

That enables me to use the ^P and ^N as normal backward and forward search if I don’t enter any text, and as filtered search if I do.

Answered By: Slobodan Ilic

Because I use oh-my-zsh, and I use the substring solution from joelostblom, James,
I modify the .zshrc like this: (which at line 13, find the line “source $ZSH/oh-my-zsh.sh
“, then modify code around it.)

plugins=(
  git
  history-substring-search
)

source $ZSH/oh-my-zsh.sh

bindkey -v
bindkey "^[[A" history-substring-search-up
bindkey "^[[B" history-substring-search-down
Answered By: SCOTT

Non-Oh-My-Zsh answer

This worked for me (on macOS) to get substring history easily accessible via up/down arrow. The key binding is up to you.

Substring search history is better than just accessing commands that start with a string. This is more like ctrl-r in most cases, those without globs or regex matching.

Starting from instructions at zsh-users/zsh-history-substring-search

brew install zsh-history-substring-search

# add the following to .zshrc
source /usr/local/share/zsh-history-substring-search/zsh-history-substring-search.zsh
bindkey '^[[A' history-substring-search-up
bindkey '^[[B' history-substring-search-down

Now enjoying this thoroughly.

Answered By: Merlin

None of the existing answers begin an incremental search with what’s been typed so far, like the question asked. This is actually possible:

_history-incremental-search-backward () {
    zle .history-incremental-search-backward -- $BUFFER
}
zle -N history-incremental-search-backward _history-incremental-search-backward

# this line is actually not necessary since this is default.
bindkey '^R' history-incremental-search-backward
  • we make a custom zle widget to wrap history-incremental-search-backward and pass the $BUFFER variable which contains the contents of the zsh prompt typed so far. You can then continue typing in the minibuffer to further narrow your search.

Naming the function after the widget allows us to simplify the code:

history-incremental-search-{back,for}ward() zle .$WIDGET -- $BUFFER
zle -N history-incremental-search-backward
zle -N history-incremental-search-forward

(here also extended to do it also for the forward search)

$BUFFER expands to the full contents of the editing buffer, replace with $LBUFFER if you only want to search based on what’s left of the cursor.

Screenshots

  • start typing a command

    enter image description here

  • realize you want to search in your history, press Ctrl-R, a minibuffer is opened and filled with the contents of the command line. As such, it first matches the command line just typed:

    enter image description here

  • press Ctrl-R again, it matches a previous command, Tab or Ctrl-E to accept the result.

    enter image description here

  • or continue typing to refine the search further

    enter image description here

To avoid the first backward search matching on the current buffer, we can empty the buffer before calling the original search widget and restore it upon failure:

history-incremental-search-{back,for}ward() {
  local saved_BUFFER=$BUFFER saved_CURSOR=$CURSOR error
  BUFFER=
  zle .$WIDGET -- $saved_BUFFER
  error=$?
  if (( error )) BUFFER=$saved_BUFFER CURSOR=$saved_CURSOR
  return error
}
zle -N history-incremental-search-backward
zle -N history-incremental-search-forward
Answered By: jameh

For those who want to know more about jasonwryan’a answer

This is the mentioned file:

# function history-search-end {
#
# This implements functions like history-beginning-search-{back,for}ward,
# but takes the cursor to the end of the line after moving in the
# history, like history-search-{back,for}ward.  To use them:
#   zle -N history-beginning-search-backward-end history-search-end
#   zle -N history-beginning-search-forward-end history-search-end
#   bindkey '...' history-beginning-search-backward-end
#   bindkey '...' history-beginning-search-forward-end

integer cursor=$CURSOR mark=$MARK

if [[ $LASTWIDGET = history-beginning-search-*-end ]]; then
  # Last widget called set $MARK.
  CURSOR=$MARK
else
  MARK=$CURSOR
fi

if zle .${WIDGET%-end}; then
  # success, go to end of line
  zle .end-of-line
else
  # failure, restore position
  CURSOR=$cursor
  MARK=$mark
  return 1
fi
# }

zle -N widget [ function ] : Create a user-defined widget.
When the new widget is invoked from within the editor, the specified shell function is called.
If no function name is specified, it defaults to the same name as the widget.
It is recommended that user-defined widgets should not have names starting with ..

# To make  history-beginning-search-{back,or}ward-end  an alias    for history-search-end
zle -N history-beginning-search-backward-end history-search-end
zle -N history-beginning-search-forward-end history-search-end
# why `history-beginning-search-{back,or}ward-end` is chosen?
# There is widgets named `history-beginning-search-{back,or}ward`,
# so just add 'end' to them, showing their relevance.

I think, (not quite sure), without this line if [[ $LASTWIDGET = history-beginning-search-*-end ]] in the file above file, the code

zle -N history-beginning-search-backward-end history-search-end
zle -N history-beginning-search-forward-end history-search-end
bindkey "^[[A" history-beginning-search-backward-end
bindkey "^[[B" history-beginning-search-forward-end

can be replaced by:

bindkey "^[[A" history-search-end
bindkey "^[[B" history-search-end
# less word to type

(Just to show the usage of zle and bindkey.
Now that we have that if line, don’t use the simplified one.)

zsh’s bindkey command

bindkey -v: select viins keymap and bind it to main
bindkey -e: select emacs keymap and bind it to main

-A : create alias (aka link)
bindkey -A viins main makes viins an alias for main

Either emacs or viins is linked to the name main.

If one of the VISUAL or EDITOR environment variables contain the string vi when the shell starts up,
then it will be viins,
otherwise it will be emacs.

Create a new keymap from emacs:

  • bindkey -N mymapname emacs

To use "mymap":

  • bindkey -A mymapname main
Answered By: Good Pen

My recommended solution for searching history with the text already entered at the prompt in zsh is to use the fzf utility. Fzf is a versatile command-line fuzzy finder that can greatly enhance your history search experience. Here’s how you can set it up:

Install fzf: You can find installation instructions for fzf on its GitHub repository (https://github.com/junegunn/fzf). Follow the installation steps specific to your operating system.

Configure fzf in your ~/.zshrc file: Open the ~/.zshrc file in a text editor and add the following line at the end of the file:

source ~/.fzf.zsh

This line ensures that fzf is sourced every time you start a new zsh session.

Save the changes and open a new terminal tab or restart your terminal for the changes to take effect.

To search history with the text already entered at the prompt, simply press Ctrl+R as before. However, this time, the fzf utility will be activated, providing an interactive search experience.

Start typing the command or text you want to search for, and fzf will filter the history based on your input in real-time.
You can use the Up and Down arrow keys to navigate through the search results.
Press Enter to execute the selected command, or press Ctrl+C to cancel the search and return to the prompt without executing any command.

By integrating fzf into your zsh configuration, you’ll have a powerful and efficient way to search your command history, even when you’ve already entered text at the prompt.

Open a new tab and press CTRL+R

You should see the following:

enter image description here

Answered By: HMagdy
Categories: Answers Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.