Jakub Piotr Cłapa

Jakub Piotr Cłapa

Read more posts by this author.

2 min read

Shell history is one of the best tools for augmenting our intellect when working with Unix apps. Remembering arcane incantations is no longer required if you can easily summon each and every one you used in the past 10 years. Here are a few helpful tricks I gathered over the years which helped me get the most of my shell history.

Avoid the export builtin

Your shell history will be more useful if you mostly avoid using the export builtin and instead set variables on the same line with the command that needs them. For example:

CFLAGS="-arch i386" CXXFLAGS="-arch i386" LDFLAGS="-arch i386" ./configure

Such command line may get quite long but you can rerun this oneliner again next year just by searching for it in your history. In your own shell scripts this can be used as a replacement for keyword arguments when you do not remember the syntax for getopt.

This method only sets the variables for a single command so exporting a variable is still a good idea if you need to change something for the whole session.

Trying to remember this long docker command you ran last week? What if you only needed to write docker and press the up arrow?

Normally pressing the up arrow will bring up previous commands one-by-one but if you are a frequent shell user chances are that the command you are looking for is probably buried quite deep. Ctrl-R does bring up an incremental search widget but navigating it requires peculiar key bindings which I'll never remember. With the two lines shown below any tool using readline will do a prefix search with whatever is currently typed to the left of your cursor:

"\e[A": history-search-backward
"\e[B": history-search-forward
Add these two lines to the ~/.inputrc file (these work in any program using readline, not only in bash and zsh).

Better Ctrl-R

I did mention that Ctrl-R is frustrating, didn't I? While frustrating and antique it is quite useful when you remember something about the arguments or files involved but not the command name (so the up-arrow prefix search is not useful).

Certainly the quickest tool to find something in your shell history is grep.

[jpc@jpc a-dox] grep ./configure ~/.zhistory
: 1615894760:0;CPPFLAGS="-I/opt/homebrew/opt/gettext/include -I/opt/homebrew/opt/ncurses/include" LDFLAGS="-L/opt/homebrew/opt/gettext/lib -L/opt/homebrew/opt/ncurses/lib" LIBS=-lintl LIBTOOL=/opt/homebrew/bin/glibtool ./configure --enable-local
Grepping through 10 years of shell history (every line begins with a timestamp, the actual command begins after the ;). If you use bash, replace .zhistory with .bash_history.

It's an amazingly good way to find what you are looking for mostly because you can see all related items at once instead of checking them one at a time with Ctrl-R. You can also quite easily copy and paste a series of commands into an editor to clean them up and turn them into a shell script.

Btw. using your favourite editor on the history file is also very useful.

Fancier Ctrl-R

grep is great but a bit boring? We can spice it up using fzf. It's a tool written in Go that allows you to select stuff in a text-mode UI. The install script will setup a nice Ctrl-R keybinding that let's you interactively filter through your shell history to find the command you need.

Let's say I used crosstool-ng to build a toolchain for ESP8266. I know I have to run the command ./ct-ng but sometimes I set some ENV variables so it the command name does not come first on the command line:

One interesting tidbit is that hitting Enter does not replace whatever you may have typed but will paste the selected history line in-place instead. This is great if you wish to join several commands with && to make a one-liner which you can repeat with a simple up arrow.