Searching your bash history

Ever forget the exact syntax to that obscure bash command you ran weeks ago, or even that standard command you ran just yesterday? Then history is coming to the rescue.

Rather than having to disrupt your workflow and start Googling for that same stackoverflow post you visited way back, history will print out your full bash history in your terminal with all the commands you’ve ever executed, like shown in the sample below:

11827  dcu
11828  ll
11829  touch article.md
11830  nn article.md
11831  nk article.md
11832  history
11833  hg scp
11834  man history
11835  history
11836  cd ~

To execute one of the outputed commands in question, just take its number preceded by !, like !11827, and it will print out the command for you (or you can just copy it directly from the terminal output).

grep your history

But, what if you have thousands of bash commands and don’t want to scroll through all of them? Well, then we can just pipe the output to grep and search through it that way like with the below:

history | grep whateverimlookingfor

To make things even easier, we can move the history | grep command into an alias defined in our .bashrc file (or .zshrc if using the zsh shell) as shown below:

alias hg="history|grep "

After refreshing your terminal or sourcing your .bashrc / .zshrc file, searching your history is as easy as running hg searchterm. For example, we can run hg scp to get the full syntax to that scp command that I've used multiple times but still don't have memorized.

 7589  scp sfh:/root/.ssh/authorized_keys .
 8045  scp zcrawler.sql ollie@198.199.98.165:/var/www
 8156  scp ollie@198.199.98.165:/var/log/syslog1 .
 8167  scp ollie@198.199.98.165:/var/log/syslog .
 8168  scp ollie@198.199.98.165:/var/log/syslog.1 .

multi term history search

The above hg alias is already a huge lifesaver for quickly digging up previous commands (which I know worked), rather than having to go digging through notes or Google to find things that I ran days / weeks / months / years ago. But just grepping through the history is a bit limited. For instance, what if we want to search for multiple search terms? Say I want to find a curl command, specifically made to port 9200? Well, then I can just grep again, by running something like below:

hg curl | grep 9200

While the above example will get the job done, it's not all that user-friendly, especially if we want to add even more search terms. We really need a fuzzy search option. Introducing fzf: https://github.com/junegunn/fzf

fuzzy match history search with fzf

The awesome fzf tool is easy to install on OSX using homebrew:

brew install fzf

# To install useful key bindings and fuzzy completion:
$(brew --prefix)/opt/fzf/install

Running both lines above will not only install fzf, but the second line will also automatically map it to some useful things, chief among them is ctrl + r. Running ctrl + r in your OSX terminal will normally allow you to search through your history by default, but only one line at a time and without fuzzy matching, making it pretty limited. But with fzf installed and the $(brew --prefix)/opt/fzf/install run, typing ctrl + r will bring up fzf's awesome multi-line fuzzy history search like shown below:

  11687  curl -s http://localhost:9200/history/_search\?q\=curl | jq '.hits.hits[]._source | "\(.number) \(.command)"'
  11688  curl -s http://localhost:9200/history/_search\?q\=curl | jq -r '.hits.hits[]._source | "\(.number) \(.command)"'
  11689  curl -s http://localhost:9200/history/_search\?q\=curl | jq -r '.hits.hits[]._source | "\(.number) + " " + \(.command)"'
  11690  curl -s http://localhost:9200/history/_search\?q\=curl | jq -r '.hits.hits[]._source | "\(.number) \(.command)"'
  11691  curl -s http://localhost:9200/history/_search\?q\=curl | jq -r '.hits.hits[]._source | "\(.number)" + " " + "\(.command)"'
  11692  curl -s http://localhost:9200/history/_search\?q\=curl | jq -r '.hits.hits[]._source | "\(.number)" + " test" + "\(.command)"'
  11693  curl -s http://localhost:9200/history/_search\?q\=curl | jq -r '.hits.hits[]._source | "\(.number)" + " test " + "\(.command)"'
> 11694  curl -s http://localhost:9200/history/_search\?q\=curl | jq -r '.hits.hits[]._source | "\(.number)" + " " + "\(.command)"'
  255/11840 +S
> curl localhost 9200

Now we can search through our entire bash history and easily find the exact command we were thinking about! It definitely beats having to open up Chrome and track down the stackoverflow answer you used one time back in the day. Check it out if you haven't already.

<  Home