Making the most of your Shells History on Linux and macOS

Modern UNIX shells like bash (default on Linux) and zsh (default on macOS) keep a history of all the commands you enter. The easiest way to access this history is by pressing the up and down cursor keys to browse through the last commands.

But this is only the tip of the iceberg. There are many more powerful history features that are easy to overlook. Learning them and making them second nature will help you to become much faster with a shell.

Viewing the History

The full history can be printed with the history command:

$ history
100 cd
101 vim file.txt
102 ls
103 mount
104 cat /etc/fstab
$

Of course, you can also search the output of the history command with grep if you are looking for a command that contains a specific string:

$ history | grep "fstab"

In our example this would give you this output:

104 cat /etc/fstab

When called without parameters, the history command of zsh will only return a part of the history. To get the full history enter history 1 instead. This tells the history command to print all history entries beginning with the first one.

Executing a Command by its Number

The numbers in the output of the history command are not there only for decorative purposes. They can be used to reference a command. To execute a command from the output you can enter a exclamation mark directly followed by the commands number:

$ !102
ls
...

Saving and Restoring the History

With bash you can save the current history to a file:

$ history -w ~/history.txt

To load the history from a file use:

$ history -r ~/history.txt

Executing the Last Command Again

To repeat the last command you executed you just have to enter two exclamation marks:

$ vim file.txt
$ !!
vim file.txt
...

Executing the Last Command Starting With…

If the command you want to start is not the last anymore because you entered some other commands in the meantime you can still execute it by entering an exclamation mark and enough characters to make it distinct from the commands you entered after it:

$ vim file.txt
$ ls
$ !vim
vim file.txt
...

Fixing the Last Command by Replacing a Substring

If you made a typo in the previous command you can fix it with the ^^ command:

$ vim ViewCnotroller.cpp
$ ^no^on
vim ViewController.cpp

The string after the first caret is the string the search for and the string after the second caret is the string to replace it with.

In case you want to delete a part of the last command you can just omit the string behind the second caret. But you can even omit the second caret:

$ vim ViewController.cpp
$ ^View
vim Controller.cpp

Reusing Parameters from the Last Command

The last word (in most cases a parameter) of the previous command is always stored in the shell variable $_. Therefore, you can use it freely at any position within the next command:

$ vim file.txt
$ cp $_ /media/usbstick

If you want to get another word from the previous command you can get it by its index (counting starts from 0) with the !:n command:

$ touch file1.txt file2.txt test3.txt
$ vim !:2
vim file2.txt
...

You can also reuse the last arguments of the previous command beginning from a certain index on the current command line by using the !:n* command:

$ touch file1.txt file2.txt test3.txt
$ vim !:2*
vim file2.txt file3.txt
...

You could use !:1* to select all the arguments of the previous command. But if you really want all arguments you can use the shorter !* command instead:

$ touch file1.txt file2.txt test3.txt
$ vim !*
vim file1.txt file2.txt test3.txt
...

Interactive Search

We’ve already seen that you can search the history with the grep command. A faster way to search the history is by using its interactive search feature.

To enable it you just have to press CTRL-R. Then you enter the search term. It will show you the most recent match directly on the command line. If this is not the match you are looking for you can either enter more characters to narrow down your search or press CTRL-R repeatedly to cycle through the matches.

Once you find your match you can either press Enter to execute the command or use the usual movement keys to edit the command to your liking.

Leave a comment