124

I recently switched from bash to zsh. In bash, one way (besides recursive search) that I used to find previously-run commands was history | grep whatever, where whatever is the bit of command I remember.

In zsh, this isn't working. history returns only a few items, even though my .zsh_history file contains many entries, which I have configured it to do.

How can I output my whole history, suitable for searching with grep?

1

4 Answers 4

173

History accepts a range in zsh entries as [first] [last] arguments, so to get them all run history 0.

To get the zsh help (at least with mind) type Alt-h over the history command and this will bring up the help for built-ins.

9
  • 8
    Great! That's an annoying default for me, though, so I'm adding this to my aliases file: alias history="history 0" Jan 12, 2011 at 22:06
  • 12
    Not that it matters but the history list starts at 1 and not 0. Dec 2, 2011 at 14:40
  • 9
    I'm using this alias myself: alias h='history 1 | grep' Apr 2, 2016 at 15:03
  • 4
    This doesn't seem to work for me: my ~/.zsh_history has 10066 lines, but history 0 (or its equivalent, fc -l 0), only prints out 4999 lines.
    – jayhendren
    May 31, 2017 at 17:29
  • 16
    To the history 1 | grep people, I hope you know about ctrl+r - best trick/shortcut ever!
    – Emil Vatai
    Mar 9, 2019 at 1:38
43

The accepted answer is correct, but it’s worth noting that you don’t need to call the external grep binary to do the search, since that ability is baked in. I have this function defined in my .zshrc:

histsearch() { fc -lim "*$@*" 1 }

Notes:

  • fc is the zsh builtin that controls the interactive history. history is equivalent to fc -l.

  • The -m flag requires a pattern, which must be quoted.

  • The -i flag adds a timestamp.

  • fc has many more tricks up its sleeve (e.g. limiting the search to internal history for the current session). See the zshbuiltins(1) man page or the official documentation.

Edit (2021-01-27):

A major advantage of using this method over just grepping the zsh history file is you get human-readable timestamps via -i. Of course, this only works if you’ve enabled the saving of timestamps to the history file in the first place:

setopt EXTENDED_HISTORY

Over the years, I’ve also added the -D flag to my function, which shows the runtime of the command in history. (This is again dependent on EXTENDED_HISTORY.) Plus, I’ve renamed the function to hgrep, which I find easier to remember:

hgrep () { fc -Dlim "*$@*" 1 }
7
  • 3
    Better yet is to use "*$@*" (note additional stars) pattern instead of "$@" as the latter yields only exact matches. May 7, 2018 at 11:50
  • 2
    You’re completely right, @PiotrDobrogost! I’m not sure how I managed to submit this answer in the state that I did — I’m guessing I must’ve typed that function from memory. As it stands it’s not very usable, so I’m going to edit the answer to incorporate the asterisks.
    – wjv
    May 7, 2018 at 13:15
  • 1
    I just switched to zsh from bash, this helped me out. I wished I had this tip years ago. All that time I've been foolishly using grep.
    – Halfstop
    Apr 24, 2020 at 13:53
  • Using grep is certainly not "foolish", @Halfstop. In fact, I would say it's the obvious thing to do, and probably how most people would accomplish this task daily. My answer is more of a "zsh insider alternative". (But it turns out that it does have certain advantages, as I pointed out in the edit I made to the answer in January this year.)
    – wjv
    Apr 6, 2021 at 8:04
  • The 2nd quote in the last command is probably a typo.
    – Teddy C
    Sep 9, 2021 at 7:01
7

Have a look at fzf. It helps not only finding "whatever-particles" in your shell history, but also in other interesting places, e.g. browser history, directory history, etc.

fzf is a command-line fuzzy finder. That means you can search for particles or fractions of what you are looking for and it will display a collection of matches which you can continuously refine. It's really a game changer.

The homepage of the author contains a number of illustrative examples.

2
  • Consider adding some reference to this answer supporting what you state. Oct 9, 2017 at 22:44
  • Welcome to Super User! Please read How to recommend software for minimum required information and suggestions on how to recommend software on Super User. To keep your answer useful even if the provided link(s) breaks these details should be edited into your answer. Oct 9, 2017 at 23:31
0

Using FZF with History

Including the suggestion from other threads here I found the best way (for me at least) to achieve searching my history using fzf.

  1. Ensure you have already installed fzf first, also you will need bat.
  2. Configure your fzf as (put this in your alias)
 #########################################################
#             CHECK THE BINARY OF FZF
# URL: https://github.com/Homebrew/brew/blob/master/docs/\
# FAQ.md#why-is-the-default-installation-prefix-opthomebrew-on-apple-silicon
#########################################################
case $(uname -s) in
"Darwin")
  if [ "$(uname -m)" = "arm64" ]; then
    fzf_binary="/opt/homebrew/bin/fzf"
  elif [ "$(uname -m)" = "x86_64" ]; then
    fzf_binary="/usr/local/bin/fzf"
  fi
  ;;
"Linux")
  if [ "$(uname -m)" = "x86_64" ]; then
    fzf_binary="/home/linuxbrew/.linuxbrew/bin/fzf"
  fi
  ;;
esac

alias fzf="$fzf_binary --preview-window top:30 --preview '([[ -f {} ]] && (bat --style=numbers --color=always\
     {} || bat {})) || ([[ -d {} ]] && (tree -C {} | less)) || echo {} 2> /dev/null | head -200'"

  1. Pip the history 0 to the fzf using
history 0 | fzf

You should be able smoothly to find any command in the past enter image description here

You must log in to answer this question.

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