"Linux users who forget history are doomed to type too much."
And that is why the powerful history command (including the Bash shell's history variant) is incredibly useful for not only repeatedly invoking previously executed commands without having to retype them, but also for recalling otherwise seldom used commands, saving you the hassle of having to research their usage anew. The command produces a chronological list of previously executed commands.
By submitting your email address, you agree to receive emails regarding relevant topic offers from TechTarget and its partners. You can withdraw your consent at any time. Contact TechTarget at 275 Grove Street, Newton, MA.
An example of the output of this command follows:
62 rm 092210.sql
64 mysqldump -u root -p dev_gamenomad_com > 092210.sql
65 more 092210.sql
66 rm 092210.sql
9991 mkdir chapter05
9992 cd chapter05
9994 npm install websocket-server
9995 node hello.js
The sequence number associated with each command serves an important purpose, allowing the user to execute the associated command anew by supplying the sequence number directly following an exclamation mark, like this:
sudo /etc/init.d/apache2 start
* Starting web server apache2
But that’s not all. The Linux history command is capable of much more, as will be covered in this tip.
Mastering history expansion
Pressing the up arrow will display the previously executed command, and pressing the Enter key will execute it anew. But a second, possibly faster option involving a feature known as history expansion is also available:
If you were repeatedly executing varying sequences of the same two or three commands, you also have the option of executing a command that appeared somewhere previous to the last command by identifying its negative index offset. For example to execute the command that was executed prior to the previous (two commands back), use the following sequence:
Another way to execute an earlier command is to type the beginning of the command sequence following the exclamation point. The first command matching that string will be executed. For example, suppose the last three commands looked like this:
9876 build-book /home/wjgilmore/easy_php
9877 mkdir chapter05
9878 cd chapter05
9879 touch chapter05.md
You can execute the build-book script again simply by running the following command:
Creating a new directory and navigating to enter it in a two step process can be shortened using history expansion. In this example, I created a new directory named easy_bash, located in /home/wjgilmore/books. To enter that directory use the !$ to obtain the last "word" found in the previous command:
$ mkdir /home/wjgilmore/books/easy_bash
$ cd !$
Searching the command history
While it's certainly possible to page through the command history (or use the grep command), it is possible to recall a fragment of the command after opening up the option to search for it using Ctrl+R. After pressing Ctrl+R, the command line prompt will look like this:
Start typing the command fragment, and the command line will update in real-time to reflect the closest match. This is what the command line looks like after typing apa:
(reverse-i-search)`apa': sudo /etc/init.d/apache2 start
When you see the desired command, press Enter to execute it, or press the right arrow to modify the command before executing it anew.
Tweaking historical behavior
There are a number of interesting configuration changes you can make in order to control how the command history behaves. For instance the Bash shell sets the default history size to 500 entries, a limit that will quickly be reached even with minimal command-line interaction. You can increase this limit by setting the HISTSIZE variable found in your Bash configuration file (.bashrc, located in your home directory):
You'll also commonly encounter another history-related variable in .bashrc named HISTCONTROL. This variable helps to determine exactly what is saved to the history file (located in.bash_history, also found in your home directory). For instance, you might repeatedly execute the tail command when examining the latest additions to a log file, over the course of a few minutes running tail a few dozen times. It would be impractical to clutter the history file with this repetition; set the HISTCONTROL variable to ignore duplicate lines by setting it to ignoredups:
Another HISTCONTROL setting of dubious utility is ignorespace. Setting HISTCONTROL to this will result in any commands executed with a prefixed space being omitted from the history file. It seems counterproductive to not track every single command, but if you'd like to enable this feature in addition to the ignoredups setting you can set both to:
One last feature I'd like to touch upon is command substitution. Suppose you wanted to rapidly configure a bunch of virtual hosts based on a virtual host configuration file template. These command sequences can be rather long, looking something like this:
$ cp vhost.template /etc/apache2/sites-available/dev.example.com
$ cp vhost.template /etc/apache2/sites-available/forum.example.com
$ cp vhost.template /etc/apache2/sites-available/staging.example.com
Usually you would execute this sequence of commands by typing and executing the first, then arrowing up, deleting the trailing string fragment (dev.example.com), and then typing the next fragment (forum.example.com), and executing anew. Alternatively, you can use command substitution to rapidly substitute one relevant string with another, like this:
The command line already offers users considerable advantages over a point-and-click interface, allowing for task execution and operating system navigation to be carried out with speed and grace. Exploiting the history command to its fullest extent only adds to these capabilities, boosting productivity even further.
ABOUT THE AUTHOR: Jason Gilmore is founder of the publishing, training, and consulting firm WJGilmore.com. He is the author of several popular books, including "Easy PHP Websites with the Zend Framework", "Easy PayPal with PHP", and "Beginning PHP and MySQL, Fourth Edition". Follow him on Twitter at @wjgilmore.