66

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

12 Answers 12

55

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
| improve this answer | |
  • Great, thank you. I had to remove the "-end" for both bindkey commands to make them work though. I have not edited your answer because maybe there's some situation in which those are necessary? – Sean Mackesey Oct 27 '13 at 23:55
  • No problem: updated the answer with the detail you wanted clarified. – jasonwryan Oct 28 '13 at 0:07
  • 2
    @hanielabed Oh-my-Zsh is a clusterfsck; I am not at all surprised it would break something as fundamental as history search... – jasonwryan Dec 18 '15 at 6:24
  • 1
    Is there a way for the cursor to jump to the end from an empty history search, but stay the same position for a partial search? This is what happens in bash currently. – CMCDragonkai Jan 11 '17 at 4:35
  • 1
    This didn't work on macOS. I needed to use bindkey "$terminfo[kcuu1]" history-beginning-search-backward-end using zzxyz's suggestion below. – pheon Mar 13 '18 at 21:03
23

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.

| improve this answer | |
  • 22
    What does hg remind me of... Oh yeah, Mercurial! – user42117 Mar 27 '15 at 19:57
  • Of what does Hg remind me? Well, mercury, the element with atomic number 80. Also known as quicksilver, which reminds me of en.wikipedia.org/wiki/Quicksilver_(software) – David J. Jun 11 at 15:50
16

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.

| improve this answer | |
  • It is unclear what this keymapping does, the answer above explains "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." – Colin D May 31 '19 at 4:10
  • @ColinD Added a note to clarify – joelostblom Jun 4 '19 at 22:45
  • 2
    substring search is best, its a superset of command begins with. to implement without being an oh-my-zsh user I did brew install zsh-history-substring-search, checked the repo readme for instructions, I'll just go ahead and create an answer I'm really happy with the result. – Merlin Sep 8 '19 at 5:20
8

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.

| improve this answer | |
8

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]}"
)
| improve this answer | |
  • Any example where Up isn’t ^[[A? It seems to be the case for most (if not all) of my computers. – Franklin Yu Apr 10 at 6:29
  • @FranklinYu - Nothing concrete anymore, I'm afraid, but..between Cygwin, WSL, ssh into remote Ubuntu machines, Oracle machines, x-windows terminals, and various MS Windows terminals (of varying quality), it has definitely been a significant issue for me. The terminfo keys are almost always available and are definitely more reliable when they are. – zzxyz Apr 11 at 19:22
6

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.

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.

| improve this answer | |
2

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.

| improve this answer | |
1

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

| improve this answer | |
1

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

| improve this answer | |
  • How is Zaw compared to history-incremental-pattern-search-forward? Pattern searching seems to cover the use-case. For example if you want to search both foo and bar then you can search for pattern of foo*bar. – Franklin Yu Apr 10 at 6:45
  • @FranklinYu - i'd say the other advantage zaw brings to the table is it does a nice full screen search, lets you edit and bookmark history selections, and lets you do the same with other sources, plus you can add your own sources too. – Brad Parks Apr 10 at 11:28
1

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.

| improve this answer | |
1

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.

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

| improve this answer | |
0

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
| improve this answer | |
  • 1
    bindkey -v will break ctrl-a, ctrl-e. Most likely all ctrl commands. – Michael Ozeryansky Oct 15 '19 at 2:55

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.