Managing bash history

· Linux
Authors

Here is a neat piece on how to manage bash history. Deals with simple and useful tricks like preventing bash history from recording duplicate commands.

Source: http://talug.org/events/20030709/cmdline_history.html

With due acknowledgemets to the author (Jason Bechtel), I am reproducing the piece for benefit of readers.

*************************
Using Bash’s History Effectively

I will attempt here to focus on only one feature of Bash, its command history. There are other good documents on the other features of Bash. If you’re interested in anything other than the command history/recall, then this document really isn’t going to fulfill your needs.

Okay, so let’s get into it!

What is Bash? “Descended from the Bourne Shell, Bash is a GNU product, the “Bourne Again SHell.” It’s the standard command line interface on most Linux machines. It excels at interactivity, supporting command line editing, completion, and recall.” –Bash Prompt HOWTO

So, Bash is GNU software and all that that implies (GPL, free, reliable, etc.). It’s the de facto standard interface that you use to interact with the system from a command line. Bash is also highly configurable. We’re going to take advantage of that later…

The last feature mentioned as one of the major selling points of Bash is “recall”. This is what I’ve been calling the command history. When typing commands at the command line interface (CLI), one can sometimes come up with rather long commands.

While completion (feature #2) alleviates much of the pain associated with entering long commands and deserves an entire presentation unto itself (stay tuned), completion also adds to the problem in a way, by making longer commands more acceptable. If we didn’t have completion, we might not name our files “really_big_file.txt.old.do_not_delete_yet”.

There’s also the advent of long options, prevalent in the GNU world. So, instead of netstat -rn you might have netstat –route –numeric.

Then, of course, there’s always the endless stringing together of commands with pipes (|) to make mini programs (my personal favorite).

So, we have this problem where command lines can get very long. Well, it’s one thing to build up long commands once. The frustration comes in having to build them up repeatedly. The obvious solution is to store commands entered on the command line and provide access to those stored commands so that they can be used again with relative ease.

That is Bash’s history/recall function in a nutshell. You just press the up arrow to scroll back through your command history. See the command you want and press Enter/Return to execute it again.

Now if that were all there was to command history, it would be pretty weak. Naturally, one might want to improve upon a previous command and Bash uses GNU Readline to provide full editing capabilities at the command-line. So, say you have a command like this:

ls -latrh /home/jason/Documents | grep work

Then you realize that you meant to do a case-insensitive grep, so you hit the up arrow and recall the command. Your cursor is sitting at the end of the line. All you have to do is arrow back four times (or just type meta-b) and type “-i “:

ls -latrh /home/jason/Documents | grep -i work

A total of 5 keystrokes, not including the added text and pressing Enter, both of which you would’ve had to do anyway. Using Readline’s meta-b shortcut saves another two keystrokes… truly efficient.

Okay, well say you didn’t just run the sought-after command. You know you’ve used it within the past few days, but you don’t want to scroll through what could be hundreds of commands to find it. Well, there are a couple ways to do this, depending on how much you can remember about the history yourself…

special knowledge
If you know you haven’t executed any commands with the same starting letter sequence since then, you can just use the built-in Bash history expansion command ! followed by the first few letters of the command.

The unique string doesn’t have to be at the start of the command. You can use the more flexible built-in Bash history expansion command !? followed by a unique string appearing anywhere in the command.

Both of these commands will immediately recall and execute the most recent matching command. Thus, it is usually not a good idea to use these methods with destructive commands like rm!

some knowledge
If you aren’t positively sure of what would happen if you were to use the ! or !? method, or if you need to search for something more unique in the command than the first few letters can provide, then you could use the history search feature.

Before you begin typing your command, type ctrl-r. This will put you into history search mode (actually, reverse incremental history search mode).

Now when you begin typing, the most recent command matching what you’ve typed so far will appear on the line with a cursor at the start of the match. (Try playing around with this feature; there are a few interesting behaviors in there.)

When you’ve found what you’re looking for, you have a couple options. Just pressing Enter will immediately recall and execute the command. ctrl-j or Escape will retrieve the command, but allow you to continue editing. If you can’t find what you’re looking for or if you just change your mind, hit ctrl-g or ctrl-c to cancel.

vague memory
If you really are uncertain of the history or if you know you could be searching back through many similar commands for one of particular interest, then you can use this more brute-force method.

Type the following command to get a list of all related commands with their history numbers:

history | grep -i “”

Once you’ve found the command you want, you can execute it specifically by its number using the following built-in history expansion command:

!

Remember: Once you’ve used one of these methods to recall and execute a command, that command is now the most recent command in your history. You can now just press the up arrow once to retrieve it again.

Okay, so now you can recall commands with relative ease. But we really haven’t done anything special yet. We’re just using the default behaviors and commands provided in Bash. The trick comes in configuring what gets put into your history!

A little-known trick (I’ve only seen one distro ship with this turned on by default) is that you can filter what gets stored in the command history. This is done merely by setting an environment variable, $HISTIGNORE.

Just set the HISTIGNORE variable to a colon-delimited list of patterns which should be excluded. There’s also the special pattern ‘&’, which suppresses duplicate entries (very useful!).

Here’s an example that suppresses duplicate commands, the simple invocation of ‘ls’ without any arguments, and the shell built-ins bg, fg, and exit:

export HISTIGNORE=”&:ls:[bf]g:exit”

Try it out. I think you’ll like it.

Here’s a neat trick, submitted by Robert Cymbala. If you include the expression “[ \t]*” in the HISTIGNORE string, you can suppress history recording at will for any given command just by starting with a space!

Another optional feature of Bash history filtering that isn’t always enabled by default in distributions is cmdhist. This determines whether multi-line commands are stored in the history as a single command (on) or not (off; default). This makes it much easier to go back and edit multi-line commands.

To enable this feature, you would type

shopt -s cmdhist

To disable this feature, you would type

shopt -u cmdhist

As you may have guessed, there are many options for Bash that can be toggled using the ‘shopt’ built-in. They are documented about halfway down this page.

There exist many more interesting things that can be done with Bash’s command history. I refer those interested in further details to the official Bash Reference at the GNU website. For more on the various special shell variables used by Bash, see this page and (search for “HIST”).

I hope this has been an approachable and useful tour of Bash’s command history feature.

V.

%d bloggers like this: