CLI Magic: Using command history in the bash shell

723

Author: Mark Sobell

The Bourne Again Shell’s history mechanism, a feature adapted from the C Shell, maintains a list of recently issued command lines, also called events, providing a quick way to reexecute any of the events in the list. This mechanism also enables you to execute variations of previous commands and to reuse arguments from them. You can replicate complicated commands and arguments that you used earlier in this login session or in a previous one and enter a series of commands that differ from one another in minor ways. The history list also serves as a record of what you have done. It can prove helpful when you have made a mistake and are not sure what you did, or when you want to keep a record of a procedure that involved a series of commands.

User Level: Intermediate

This article is excerpted from chapter 9 of the new Third Edition of A Practical Guide to Red Hat Linux: Fedora Core and Red Hat Enterprise Linux, copyright 2007 Pearson Education, Inc. ISBN 0132280272. Published June 2006 by Prentice Hall Professional. Reproduced by permission of Pearson Education, Inc. All rights reserved.

Variables that control history

The value of the HISTSIZE variable determines the number of events preserved in the history list during a session. A value in the range of 100 to 1,000 is normal.

When you exit from the shell, the most recently executed commands are saved in the file given by the HISTFILE variable (the default is ~/.bash_history). The next time you start the shell, this file initializes the history list. The value of the HISTFILESIZE variable determines the number of lines of history saved in HISTFILE (not necessarily the same as HISTSIZE). HISTSIZE holds the number of events remembered during a session, HISTFILESIZE holds the number remembered between sessions, and the file designated by HISTFILE holds the history list.

Variable

Default

Function

HISTSIZE

500 events

Maximum number of events saved during a session

HISTFILE

~/.bash_history

Location of the history file

HISTFILESIZE

500 events

Maximum number of events saved between sessions

The Bourne Again Shell assigns a sequential event number to each command line. You can display this event number as part of the bash prompt by including ! in the PS1 variable. Examples in this article show numbered prompts when they help to illustrate the behavior of a command.

Give the following command manually or place it in ~/.bash_profile (to affect future sessions) to establish a history list of the 100 most recent events:

$ HISTSIZE=100

The following command causes bash to save the 100 most recent events across login sessions:

$ HISTFILESIZE=100

After you set HISTFILESIZE, you can log out and log in again, and the 100 most recent events from the previous login session will appear in your history list.

Give the command history to display the events in the history list. The list of events is ordered with oldest events at the top of the list. The following history list includes a command to modify the bash prompt so that it displays the history event number. The last event in the history list is the history command that displayed the list.

32 $ history | tail
   23  PS1="! bash$ "
   24  ls -l
   25  cat temp
   26  rm temp
   27  vim memo
   28  lpr memo
   29  vim memo
   30  lpr memo
   31  rm memo
   32  history | tail

As you run commands and your history list becomes longer, it may run off the top of the screen when you use the history builtin. Pipe the output of history through less to browse through it, or give the command history 10 to look at the 10 most recent commands.

You can reexecute any event in the history list. Not having to reenter long command lines allows you to reexecute events more easily, quickly, and accurately than you could if you had to retype the entire command line. You can recall, modify, and reexecute previously executed events in three ways: You can use the fc builtin (covered next); the exclamation point commands; or the Readline Library, which uses a one-line vi- or emacs-like editor to edit and execute events.

If you are more familiar with vi or emacs and less familiar with the C or TC Shell, use fc or the Readline Library. If you are more familiar with the C or TC Shell and less familiar with vi and emacs, use the exclamation point commands. If it is a toss-up, try the Readline Library; it will benefit you in other areas of Linux more than learning the exclamation point commands will.

Next: Using fc

fc: Displays, Edits, and Reexecutes Commands

The fc (fix command) builtin enables you to display the history list and edit and reexecute previous commands. It provides many of the same capabilities as the command line editors.

When you call fc with the -l option, it displays commands from the history list. Without any arguments, fc -l lists the 16 most recent commands in a numbered list, with the oldest appearing first:

$ fc -l
1024     cd
1025     view calendar
1026     vim letter.adams01
1027     aspell -c letter.adams01
1028     vim letter.adams01
1029     lpr letter.adams01
1030     cd ../memos
1031     ls
1032     rm *0405
1033     fc -l
1034     cd
1035     whereis aspell
1036     man aspell
1037     cd /usr/share/doc/*aspell*
1038     pwd
1039     ls
1040     ls man-html

The fc builtin can take zero, one, or two arguments with the -l option. The arguments specify the part of the history list to be displayed:

fc -l [ first[last[[

The fc builtin lists commands beginning with the most recent event that matches first. The argument can be an event number, the first few characters of the command line, or a negative number, which is taken to be the nth previous command. If you provide last, fc displays commands from the most recent event that matches first through the most recent event that matches last. The next command displays the history list from event 1030 through event 1035:

$ fc -l 1030 1035
1030     cd ../memos
1031     ls
1032     rm *0405
1033     fc -l
1034     cd
1035     whereis aspell

The following command lists the most recent event that begins with view through the most recent command line that begins with whereis:

$ fc -l view whereis
1025     view calendar
1026     vim letter.adams01
1027     aspell -c letter.adams01
1028     vim letter.adams01
1029     lpr letter.adams01
1030     cd ../memos
1031     ls
1032     rm *0405
1033     fc -l
1034     cd
1035     whereis aspell

To list a single command from the history list, use the same identifier for the first and second arguments. The following command lists event 1027:

$ fc -l 1027 1027
1027     aspell -c letter.adams01

You can use fc to edit and reexecute previous commands.

fc [-e  editor] [first[last[[

When you call fc with the -e option followed by the name of an editor, fc calls the editor with event(s) in the Work buffer. Without first and last, fc defaults to the most recent command. The next example invokes the vi(m) editor to edit the most recent command:

$ fc -e vi

The fc builtin uses the stand-alone vi(m) editor. If you set the FCEDIT variable, you do not need to use the -e option to specify an editor on the command line. Because the value of FCEDIT has been changed to /usr/bin/emacs and fc has no arguments, the following command edits the most recent command with the emacs editor:

$ export FCEDIT=/usr/bin/emacs
$ fc

If you call it with a single argument, fc invokes the editor on the specified command. The following example starts the editor with event 21 in the Work buffer. When you exit from the editor, the shell executes the command:

$ fc 21

Again you can identify commands with numbers or by specifying the first few characters of the command name. The following example calls the editor to work on events from the most recent event that begins with the letters vim through event 206:

$ fc vim 206

When you execute an fc command, the shell executes whatever you leave in the editor buffer, possibly with unwanted results. If you decide you do not want to execute a command, delete everything from the buffer before you exit from the editor.

You can reexecute previous commands without going into an editor. If you call fc with the -s option, it skips the editing phase and reexecutes the command. The following example reexecutes event 1029:

$ fc -s 1029
lpr letter.adams01

The next example reexecutes the previous command:

$ fc -s

When you reexecute a command you can tell fc to substitute one string for another. The next example substitutes the string john for the string adams in event 1029 and executes the modified event:

$ fc -s adams=john 1029
lpr letter.john01

Using an Exclamation Point (!) to Reference Events

The C Shell history mechanism uses an exclamation point to reference events, and is available under bash. It is frequently more cumbersome to use than fc but nevertheless has some useful features. For example, the !! command reexecutes the previous event, and the !$ token represents the last word on the previous command line.

You can reference an event by using its absolute event number, its relative event number, or the text it contains. All references to events, called event designators, begin with an exclamation point (!). One or more characters follow the exclamation point to specify an event.

You can put history events anywhere on a command line. To escape an exclamation point so that it is treated literally instead of as the start of a history event, precede it with a backslash () or enclose it within single quotation marks.

An event designator specifies a command in the history list.

Event designators

Designator

Meaning

!

Starts a history event unless followed immediately by SPACE, NEWLINE, =, or (.

!!

The previous command.

!n

Command number n in the history list.

!-n

The nth preceding command.

!string

The most recent command line that started with string.

!?string[?]

The most recent command that contained string. The last ? is optional.

!#

The current command (as you have it typed so far).

!{event}

The event is an event designator. The braces isolate event from the surrounding text. For example, !{-3}3 is the third most recently executed command followed by a 3.

You can always reexecute the previous event by giving a !! command. In the following example, event 45 reexecutes event 44:

44 $ ls -l text
-rw-rw-r--   1 alex group 45 Apr 30 14:53 text
45 $ !!
ls -l text
-rw-rw-r--   1 alex group 45 Apr 30 14:53 text

The !! command works whether or not your prompt displays an event number. As this example shows, when you use the history mechanism to reexecute an event, the shell displays the command it is reexecuting.

A number following an exclamation point refers to an event. If that event is in the history list, the shell executes it. Otherwise, the shell displays an error message. A negative number following an exclamation point references an event relative to the current event. For example, the command !-3 refers to the third preceding event. After you issue a command, the relative event number of a given event changes (event -3 becomes event -4). Both of the following commands reexecute event 44:

51 $ !44
ls -l text
-rw-rw-r--   1 alex group 45 Nov 30 14:53 text
52 $ !-8
ls -l text
-rw-rw-r--   1 alex group 45 Nov 30 14:53 text

When a string of text follows an exclamation point, the shell searches for and executes the most recent event that began with that string. If you enclose the string between question marks, the shell executes the most recent event that contained that string. The final question mark is optional if a RETURN would immediately follow it.

68 $ history 10
   59  ls -l text*
   60  tail text5
   61  cat text1 text5 > letter
   62  vim letter
   63  cat letter
   64  cat memo
   65  lpr memo
   66  pine jenny
   67  ls -l
   68  history
69 $ !l
ls -l
...
70 $ !lpr
lpr memo
71 $ !?letter?
cat letter
...

Optional – Word Designators

A word designator specifies a word or series of words from an event.

Word designators

Designator

Meaning

n

The nth word. Word 0 is normally the command name.

^

The first word (after the command name).

$

The last word.

mn

All words from word number m through word number n;m defaults to 0 if you omit it (0-n).

n*

All words from word number n through the last word.

*

All words except the command name. The same as 1*.

%

The word matched by the most recent ?string? search.

The words are numbered starting with 0 (the first word on the line — usually the command), continuing with 1 (the first word following the command), and going through n (the last word on the line).

To specify a particular word from a previous event, follow the event designator (such as !14) with a colon and the number of the word in the previous event. For example, !14:3 specifies the third word following the command from event 14. You can specify the first word following the command (word number 1) by using a caret (^) and the last word by using a dollar sign ($). You can specify a range of words by separating two word designators with a hyphen.

72 $ echo apple grape orange pear
apple grape orange pear
73 $ echo !72:2
echo grape
grape
74 $ echo !72:^
echo apple
apple
75 $ !72:0 !72:$
echo pear
pear
76 $ echo !72:2-4
echo grape orange pear
grape orange pear
77 $ !72:0-$
echo apple grape orange pear
apple grape orange pear

As the next example shows, !$ refers to the last word of the previous event. You can use this shorthand to edit, for example, a file you just displayed with cat:

$ cat report.718
...

$ vim !$
vim report.718
...

If an event contains a single command, the word numbers correspond to the argument numbers. If an event contains more than one command, this correspondence does not hold true for commands after the first. In the following example, event 78 contains two commands separated by a semicolon so that the shell executes them sequentially; the semicolon is word number 5.

78 $ !72 ; echo helen jenny barbara
echo apple grape orange pear ; echo helen jenny barbara
apple grape orange pear
helen jenny barbara
79 $ echo !78:7
echo helen
helen
80 $ echo !78:4-7
echo pear ; echo helen
pear
helen

On occasion you may want to change an aspect of an event you are reexecuting. Perhaps you entered a complex command line with a typo or incorrect pathname, or you want to specify a different argument. You can modify an event or a word of an event by putting one or more modifiers after the word designator, or after the event designator if there is no word designator. Each modifier must be preceded by a colon (:).

The substitute modifier is more complex than the other modifiers. The following example shows the substitute modifier correcting a typo in the previous event:

$ car /home/jenny/memo.0507 /home/alex/letter.0507
bash: car: command not found
$ !!:s/car/cat
cat /home/jenny/memo.0507 /home/alex/letter.0507
...

The substitute modifier has the following syntax:

[g]s/old_/new_/

where old is the original string (not a regular expression), and new is the string that replaces old. The substitute modifier substitutes the first occurrence of old with new. Placing a g before the s (as in gs/old/new/) causes a global substitution, replacing all occurrences of old. The / is the delimiter in the examples, but you can use any character that is not in either old or new. The final delimiter is optional if a RETURN would immediately follow it. As with the vim Substitute command, the history mechanism replaces an ampersand (&) in new with old. The shell replaces a null old string (s//new/) with the previous old string or string within a command that you searched for with ?string?.

An abbreviated form of the substitute modifier is quick substitution. Use it to reexecute the most recent event while changing some of the event text. The quick substitution character is the caret (^). For example, the command

$ ^old^new^

produces the same results as

$ !!:s/old/new/

Thus substituting cat for car in the previous event could have been entered as

$ ^car^cat
cat /home/jenny/memo.0507 /home/alex/letter.0507
...

You can omit the final caret if it would be followed immediately by a RETURN. As with other command line substitutions, the shell displays the command line as it appears after the substitution.

Modifiers (other than the substitute modifier) perform simple edits on the part of the event that has been selected by the event designator and the optional word designators. You can use multiple modifiers, each preceded by a colon (:).

The following series of commands uses ls to list the name of a file, repeats the command without executing it (p modifier), and repeats the last command, removing the last part of the pathname (h modifier), again without executing it:

$ ls /etc/sysconfig/harddisks
/etc/sysconfig/harddisks
$ !!:p
ls /etc/sysconfig/harddisks
$ !!:h:p
ls /etc/sysconfig
$

This table lists event modifiers other than the substitute modifier.

Modifiers

Modifier

Function

e (extension)

Removes all but the filename extension

h (head)

Removes the last part of a pathname

p (print-not)

Displays the command, but does not execute it

q (quote)

Quotes the substitution to prevent further substitutions on it

r (root)

Removes the filename extension

t (tail)

Removes all elements of a pathname except the last

x

Like q but quotes each word in the substitution individually