A little bit of history

Just about anyone who works on the command line of a Unix/Linux systems knows about history. Having the ability to repeat their most recent command by just typing !! or the most recent command that starts with a particular letter by typing something like !s saves them a lot of typing and a lot of typos. But these uses of the history feature of the shell only scratch the surface of what it can do for you.

You can also edit prior commands, find prior commands based on particular substrings, determine how much history is preserved for you, remove commands from your history, filter (omit) commands so they're never save in your history, and clear your history altogether.

How does the history command work? It stores the commands that you type in a history buffer that isn't written to your history file -- which might be .history or .bash_history -- until you log out. When you type history on the command line, what you see will be a combination of the commands you've typed since you started your current shell and earlier commands that were recorded in your history file.

If you start a second shell by typing /bin/bash, enter some commands, exit that shell, and type some additional commands, the commands that you entered in the subshell will appear in your history file prior to those you entered before starting the shell because that shell exited first. Try this:

$ echo 1
$ echo 2
$ echo 3
$ /bin/bash
$ echo 4
echo 5
$ exit
$ history 5
   42  echo 1
   43  echo 2
   44  echo 3
   45  /bin/bash
   46  history 5

Log off and back in and then:

$ tail .bash_history
echo 4
echo 5
echo 1
echo 2
echo 3
history 5
tail -5 .bash_history

Notice how the echoes of 1, 2 and 3 appear after 4 and 5 even though you entered those commands earlier.

Any time you start a new shell, you will see only the commands you have typed since invoking it and commands that were previously stored in your history file. Run this script and it will not see any of the commands you typed just before running it.


history 10

Run this one and it will -- because this one doesn't spawn a new shell.

history 10

You can see a portion of your history by using an argument with the history command. For example, history 5 shows you only the most recent 5 commands. You can selectively remove commands from your history file using history -d:

$ history 6
   42  echo 1
   43  echo 2
   44  echo 3
   45  echo 4
   46  echo 5
   47  history 6
$ history -d 45
$ history 6
   43  echo 2
   44  echo 3
   45  echo 5
   46  history 6
   47  history -d 45
   48  history 6

The -d option is particularly handy if you completely botched a command and want to be sure not to repeat the mistake when you re-use commands.

You can clear your history buffer with the -c argument, though the old entries in your history file will remain intact until you log off.

$ history -c

You can also modify commands and run them again by using the ^old^new^ syntax.

$ cal 10 2012
    October 2012
Su Mo Tu We Th Fr Sa
    1  2  3  4  5  6
 7  8  9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31

$ ^0^1^
cal 11 2012
   November 2012
Su Mo Tu We Th Fr Sa
             1  2  3
 4  5  6  7  8  9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30

Typing ^r (control-r) allows you to search your history for particular strings regardless of where the strings appear within your prior commands -- thus more flexible than the !l syntax. You might want to locate and re-run the last command you ran against a particular file or using a particular filter. Type ^r and you will see this prompt asking you for your search term:


How much history you preserve depends on your HISTSIZE setting. Generally set to 1000 commands, this allows you to reach back pretty far into your command history. If you don't want these lines to preserve all of your ls, pwd, bg, fg, history and exit commands, you can exclude these commands by setting your HISTIGNORE. Just remember to add a line like this to your .bash_profile.

export HISTIGNORE="&:ls:pwd:[bf]g:history:exit"

Using shopt

If you are staring at that heading and asking yourself "shopt? what's that?", you're not alone. This command isn't in the most likely Unix commands to be used. In fact, it's not really a command, but a shell built-in. So you won't find it using the which command, but the man page should provide a lot of good information. The word "shopt" doesn't suggest its use if you, like me, see "shop tee". If you can think of it instead as "sh opt" (shell options), it will be a little easier to remember. The shopt built-in allows you to toggle settings that control shell behavior, some of which affect how the history command behaves.

In the shopt output below, you can see whether various features of the shell are turned on or off. With an s (set) argument, shopt turns a feature on while with a u (unset) argument, it turns them off.

$ shopt
cdable_vars     off
cdspell         off
checkhash       off
checkwinsize    on
cmdhist         on
dotglob         off
execfail        off
expand_aliases  on
extdebug        off
extglob         off
extquote        on
failglob        off
force_fignore   on
gnu_errfmt      off
histappend      off
histreedit      off
histverify      off
hostcomplete    on
huponexit       off
interactive_comments    on
lithist         off
login_shell     on
mailwarn        off
no_empty_cmd_completion off
nocaseglob      off
nocasematch     off
nullglob        off
progcomp        on
promptvars      on
restricted_shell        off
shift_verbose   off
sourcepath      on
xpg_echo        off

If you disable the cmdhist setting by using the command shopt -u cmdhist, multi-line commands that previously would have been stored in a single line of your history file will be stored on multiple lines like so:

   21  for num in 1 2 3
   22  do
   23    echo $num is nice
   24  done

This might be useful if the complexity of your commands is all in the first line and maybe you want to issue a series of very different commands from different locations in your file systems within your do ... done. In any case, it's there should you find this option useful.

Those who cannot learn from history are bound to repeat it. Then again, so are those who do!

This article is published as part of the IDG Contributor Network. Want to Join?

To express your thoughts on Computerworld content, visit Computerworld's Facebook page, LinkedIn page and Twitter stream.
7 Wi-Fi vulnerabilities beyond weak passwords
Shop Tech Products at Amazon