Linux

Linux command line tips: history and HISTIGNORE in Bash

If you've worked in the terminal, it's likely you're in some way proficient with the command history features of your shell. There's a lot more functionality than many realise however, and learning it can help you eliminate a lot of duplicate typing.

If you've worked in the terminal, it's likely you're in some way proficient with the command history features of your shell. There's a lot more functionality than many realise however, and by learning it you can eliminate a lot of duplicate typing.

The first thing most people learn about the command history is that you can go back and forward through your history with the up and down keys. Bash stores history entries between shells by default (on most distributions), so you should have access to the commands you typed previously, regardless of which terminal you're currently working in. You can turn this behaviour off, so that history works only for the current invocation of the shell you're using by adding the following line to one of your start-up files (say, ~/.bashrc):

SAVEHIST=0

The amount of commands stored in the history file is dependent on the size of the file you allocate. By default 500 commands are stored, but you can tweak these values by setting the following options in a startup file:

HISTSIZE = 1000
HISTFILE = ~/.bash_history

To print out the entire history file, you can use the history command:

$ history | tail -10
  522  gvim
  523  vim .bashrc 
  524  vim .bash_profile 
  525  history
  526  ls
  527  echo $SHELL
  528  echo $HISTFILE
  529  echo $HISTSIZE
  530  vim .bashrc 
  531  history | tail -10
$

The number in the left column is the history item number. This can be bigger than the size of your stored history file, as commands from the current shell are not added to the file until the shell is closed.

You can jump straight to executing any line in your history by typing an '!' followed by the item number. So for example if we wanted to echo the shell name to the console again we could write echo $SHELL or simply:

$ !527
/bin/bash
$

Searching command history

You can also use the ! command to search through the history, by replacing the item number with characters from the start of the command. The previous example can now just as easily be written:

$ !echo
echo $SHELL
/bin/bash
$

Often this becomes unwieldy since you have to match the command from the beginning, and many commands start in the same way (eg. "echo $HISTFILE", "echo $HISTSIZE", "echo $SHELL"). You can always hack something together using history and grep, but there's an easier way with the '!?' command. '!?' followed by a simple string, executes the last command in the history that contains that string.

So, to reprint the name of the shell we could have simply typed:

$ !? SHELL
/bin/bash
#

More usefully, you can interactively search the command history at the console by hitting CTRL-R at the prompt and typing the section of the string you are looking for. You can only use CTRL-R interactively, that is, not in a script (although relying on the history in a script can be dangerous anyway), but it can save you more keystrokes as it displays the match at each point, meaning you can stop searching once you've found it.

The previous example using CTRL-R interactive search:

(reverse-i-search)`SH': echo $SHELL

$HISTIGNORE

The HISTIGNORE environment variable controls which commands are entered into the history and which are ignored. It contains a list of patterns separated by colons (':') that when matched, drops a command rather than includes it in the file. So for example, if you don't need to see the 'history' program in the command history (since it's fairly redundant), you could do the following:

$ export HISTIGNORE="history"
$ history
...
$ history | tail -1
	581  export HISTIGNORE="history"
	582  history | tail -1

You can see here that the line with simply history on it has not been added to the list, while the history | tail -1 has -- only exact matches in the HISTIGNORE list are filtered out. If you don't want any lines beginning with history to be in the command history you can amend your HISTIGNORE variable to:

$ export HISTIGNORE="history*"

Be warned however than ignoring an item from the history means that it cannot be recalled by any means -- not even with the up and down arrows. If you still wish to keep this behaviour for all commands, but not have them show up in a history file, you may be better served by leaving HISTIGNORE alone and trimming the file with a script on logout.

Some people use this variable to keep their history file nice and tidy, by removing the commands that they're unlikely to bother recalling, such as ls, fg or exit. Another good tip comes from this page which includes the tip that if you add "[ \t]*" to your HISTIGNORE variable you can make any command be ignored by starting it with a space. Good if you need a little extra privacy for some commands.

1 comments
Hnat Kubov
Hnat Kubov

I know this post is too old, but since it shows up in google search on "histignore", I have to add, that there's more-- em, 'built-in' way of ignoring commands that start with " ". So, instead of adding "[ \t]*" to HISTIGNORE, you can use HISTCONTROL=ignorespace. But actually I don't know if it makes any difference. Just makes your .bashrc more readable.