Don’t use “history | grep” for searching command history, use Peco

Kohei Mikami
4 min readJul 20, 2018

How long can you remember commands you typed on your terminal? If it’s less than 3 arguments, I can remember it for a day but any more than 3 then it gets difficult. What if you used the command a week ago? What if the command had more than 10 arguments includes file paths? For example:

docker run -it -shm-size 256m -net=”host” -rm -v “${PWD}/some/path:/app” -e SOME_ENV=”stage” -e ANOTHER_ENV=”another” docker/image

I definitely can’t remember exactly what commands I typed even just 30 seconds later. I know some people who try to find the command by pressing the up key many times, and it’s alright if you ran the command 5 minutes ago, but it’s hard if you did it a month ago. Also, some people usehistory | grep “command"to find it. Though it’s a slightly better solution, you still need to copy & paste from a list of commands.

What I’m going to write about is, a magical solution for this problem.

Magical filtering tool: Peco

What if you can search for commands like you search on Google? As you type whatever part of the command you remember — let’s say docker -e env, it will list all of the commands you have executed. From that list you choose a command you want to run again. Convenient, isn’t it?

There is a great command line tool called Peco, which is an interactive filtering tool written in Go. You can pass anything through pipes to filter the text. You can pass history command, ls command, text files and whatever you like. For example, you can filter files in the folder with Peco like below

ls -l | peco

Let me introduce how to use history command and Peco. On my terminal, I have a key bind(ctrl + R) to pass a command history to Peco, and paste the result into the terminal which is able to execute it immediately.

How to install

First thing you need to do is installing peco command. If you’re using Mac and homebrew, you can install with a command below. If not, follow this instruction.

$ brew install peco
...
$ peco --version
$ peco version v0.5.1

Next, you need to modify your .zshrc or .bash_rc to write a function to handle history command and bind the function to ctrl+R key.

# Peco history selection
function peco-history-selection() {
local tac
if which tac > /dev/null; then
tac="tac"
else
tac="tail -r"
fi
BUFFER=$(history -1000 | eval $tac | cut -c 8- | peco --query "$LBUFFER")
CURSOR=$#BUFFER
}
zle -N peco-history-selection
bindkey '^R' peco-history-selection

and

$ source .zshrc (or .bash_rc)

That’s it. Just press ctrl+R and you’ll see a screen like a gif above. You can type a command you’ve used like git , and it will show the command history immediately. Use arrow keys to chose a command and enter to select it. If you want to choose multiple lines, though it might not be useful for this case, you can use ctrl+space to toggle the selection.

Advanced recipe and idea for Peco

Peco is quite useful if you need to filter and choose lines. A good example is the docker command. Let’s say you need to docker stop for multiple containers. You might do docker ps to see all the running containers and copy & paste the container names to stop them.

You no longer you need to do it if you use Peco! I have an alias to select multiple containers and pass the selected docker IDs to the docker command. The example above, it runs docker inspecs and dokcer kill against multiple containers.

alias pdoc="docker ps | peco | awk '{print \$1;}' | tr '\n' ' ' | xargs docker"

Add this line into your .zshrc or .bash_rc. What this line does is run docker ps, pass it to peco, get all the first word(id) for each selected line and replace the new lines into spaces. Finally, it passes to another docker command. As a result, the output of pdoc kill will be like docker kill 113f6ed5a15f 552a2c3d2198 b497699fa26f.

Happy Peco Life!

--

--