139

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?

Nathan Long
  • 27,435

5 Answers5

190

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.

Kyle Brandt
  • 4,729
48

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 }
wjv
  • 1,131
8

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.

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

Dr Neo
  • 131
  • 3
0

Add this to your .zshrc:

alias history='fc -i -l -D 0'

It's more robust than the accepted answer because the history alias may not be correctly setup.