Linux.com

Feature

CLI Magic: Using command history in the bash shell

By Mark Sobell on July 03, 2006 (8:00:00 AM)

Share    Print    Comments   

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

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 n th 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 n th 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 n th word. Word 0 is normally the command name.

^

The first word (after the command name).

$

The last word.

m - n

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

 

Share    Print    Comments   

Comments

on CLI Magic: Using command history in the bash shell

Note: Comments are owned by the poster. We are not responsible for their content.

Privacy

Posted by: Anonymous Coward on July 03, 2006 05:37 PM
For privacy I often remove the write attribute from the<nobr> <wbr></nobr>.bash_history file to prevent bash from writing my commands down there.

#

Re:Privacy

Posted by: Anonymous Coward on July 04, 2006 02:18 AM

You can also make your<nobr> <wbr></nobr><tt>.bashrc</tt> '<tt>unset HISTFILE</tt>' to prevent bash even from trying to maintain a history file

Good for root's<nobr> <wbr></nobr><tt>.bashrc</tt> methinks...<nobr> <wbr></nobr>:-)

-Tweek

#

interactive way

Posted by: Anonymous Coward on July 03, 2006 06:29 PM
I often use ctrl-r to start an history search (reverse-i-search) : ctrl-r + you type part of a previous command (and you can ctrl-r to search further backward) and you can edit the command before pressing enter.

#

Re:interactive way

Posted by: Anonymous Coward on July 04, 2006 01:33 AM
i just found out about the emacs ^r search, which has been great (just type any portion of the command you're looking for). also, setting HISTCONTROL to ignore duplicates can way-shorten the `history -200 | less` routine

#

Re:interactive way

Posted by: Anonymous Coward on July 04, 2006 03:26 AM
One of the things that prevents my switching to bash is the absence of an equivalent to tcsh's Esc-p keybinding.

Say your history looks like this:


      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

In tcsh, if you type "l" (the letter L) followed by Esc-p, history is searched backwards for the first command that started with "l". Keep hitting Esc-p and it keeps going back in history to find the correct one.

So in this case, you would first see "lpr memo", then "ls -l", etc. If you pass the one you want, you can go back by hitting Esc-n.

In many instances, it really beats the pants off bash's Ctrl-r.

Is there the same thing in Bash?

L

#

Re:interactive way

Posted by: Anonymous Coward on July 04, 2006 04:45 PM
Yes, there is something similar, and I'm using it all the time. By changing the setting of bash you can write the start of a command and using the up or down key to cycle through history of command starting with what you typed.

for details, see (that's where I learned about this):
<a href="http://www.geocities.com/h2428/petar/bash_hist.htm" title="geocities.com">http://www.geocities.com/h2428/petar/bash_hist.ht<nobr>m<wbr></nobr> </a geocities.com>

regards,
n.

#

too much keybindings to learn

Posted by: Anonymous Coward on July 03, 2006 08:08 PM
is there any other shell that has most of the nice features of bash but without requiring you to learn all these key bindings and symbols? I mean something with a nice intuitive ncurses interface.

(mc would be nice but it has to do a lot more than that so it doesn't emphasize on the command prompt power)

#

Re:too much keybindings to learn

Posted by: Anonymous Coward on July 06, 2006 07:10 PM
No, I am not aware of any such shell.
But maybe you want to innovate the next-generation super shell?
Go ahead!<nobr> <wbr></nobr>:)

#

Re:too much keybindings to learn

Posted by: Anonymous Coward on July 07, 2006 12:00 AM
hmm... I might have been missunderstood

It's definetly not the power that I see lacking in shells like bash - to the contrary there is plenty of it. What I would like to see are convinience, easy learning curve, easy exploration of the shell capabilities etc.

That is it's not easy for a new user to use even a small part of bash capabilites. They are hiden. It's the typical "read the man page, experiment, read the man again, work for a few days, oops you forgot the shortcut? go read the man page again - after some months you are a guru, go impress your friends". I prefer the other aproach "read the first 2 pages of the manual, play with it, learn as you play, let the UI provide feedback and help you explore it, when you're really up to doing something impressive read the other manual pages and experiment a few times"

An example: I usualy forget the little important details of how to search for an html file that contains the word "linux" through the shell. I can NEVER forget how to do the same in mc - it's damn obvius. Ofcourse I can't make complex searches in mc but I could do 90% of the searches I care to do if mc had just a few more controls in the search window.

#

There's an easier way for those who use vi

Posted by: Anonymous Coward on July 05, 2006 11:28 PM
Just type "set -o vi" at the command prompt.

Now you can then recall the previous command by pressing "Esc k". Press "k" again to get the next previous command. Press "j" and you come back down the list. Press "l" or "h" to go left or right, just like in vi. You can use vi commands to edit the command.

Sure is easier than all this "fc" stuff!

#

Re:ignore duplicate &amp; commands

Posted by: Anonymous Coward on July 06, 2006 07:12 PM
Good idea to ignore some commands, then it only logs important stuff such as which files get edited, which hosts get pinged, nmapped, etc...

#

Re:Red Hat Rocks

Posted by: Anonymous Coward on July 13, 2006 02:02 AM
These aren't features of Red Hat. It's features of bash and available on any system that uses bash.

#

Red Hat Rocks

Posted by: Administrator on July 04, 2006 02:53 PM
It is this cool stuff that makes Red Hat Linux the choice for me.

#

ignore duplicate &amp; commands

Posted by: Administrator on July 04, 2006 02:28 AM
# ignore duplicate

HISTCONTROL=ignoreboth



# ignore these in history file

HISTIGNORE=ls:ll:la:l:cd:pwd:exit:mc:su:df:clear

#

This story has been archived. Comments can no longer be posted.



 
Tableless layout Validate XHTML 1.0 Strict Validate CSS Powered by Xaraya