history command, when used without any options, shows the history of commands run on the terminal. But that is not only what history and its associated libraries are famous for. They give high speed advantages to those who know how to use it well. You can search a command previously run, and rerun it without involving the efforts of typing it again. History expansions, as it is called, introduce words from the history list into the input stream, making it easy to repeat commands, insert the arguments to a previous command into the current input line, or fix errors in previous commands quickly. The below paragraph from the man page best describes how this works.
History expansion is usually performed immediately after a complete line is read. It takes place in two parts. The first is to determine which line from the history list to use during substitution. The second is to select portions of that line for inclusion into the current one. The line selected from the history is the event, and the portions of that line that are acted upon are words. Various modifiers are available to manipulate the selected words. The line is broken into words in the same fashion as bash does when reading input, so that several words that would otherwise be separated are considered one word when surrounded by quotes. History expansions are introduced by the appearance of the history expansion character, which is ! by default. Only backslash (\) and single quotes can quote the history expansion character.
Let’s start with few examples.
1. ! instructs the shell to start the history substitution. For example, I can do
$ echo "how are you" how are you
But once I have typed that, why do I need to type again and again? I can simply do :
!echo
and I get the same output. The thing here to remember is that ! does the substitution of the most recent run command. So it is important to run a commands with this expansion once you are sure what will the substitution be. !r can expand to ‘readlink file.txt’ or ‘rm *’, depending on which was run last. Be VERY sure what was run last by you before using this.
2. !n : When you type history, you see numbers associated with the command in the order in which they were run. For example:
$ history
1 dmesg
2 ifconfig
3 exit
4 ifconfig
5 exit
6 ifconfig
7 exit
8 apt-get update
9 sudo apt-get update
10 sudo apt-get install ssh
11 tcpdump -a
12 sudo apt-get install tcpdump
13 sudo tcpdump -a
14 tcpdump
15 sudo tcpdump
16 top
....
....
.... If you want to run a particular command in the list, you can use !n to run the command associated with line n. For example, if I want to run command number 11 from the above list (tcpdump -a), I can simply write !11. You can also count in the reverse order if you want, starting from 1. For example, to run the last command again, you can easily use !-1. You can also use !! to rerun the last command.
3. The power of ctrl-r: Press ctrl-r before you start typing and see the magic. As you type, the commands start appearing from the history. The moment your desired command appears, simply hit enter. It is a very useful tool to run very long commands. Below is an example, where I pressed ctrl-r, and typed only ‘ech’. It gave me the entire command. Please note how it explicitly says ‘reverse-i-search’.
(reverse-i-search)`ech': echo "how are you"
4. ^string1^string2^: If you want to replace string2 instead of string1 in the last command, use this string substitution. For example,
$ echo abc.txt abc.txt $ ^echo^cat^ cat abc.txt how are you? i am fine how about you?
5. Control the history to be maintained: You can edit your .bash_profile file to set the size of history and location of commands you want to maintain.
HISTSIZE=1000
HISTFILESIZE=1000
HISTFILE=~/.history_list
To avoid duplication of commands which occur together in the history, use
export HISTCONTROL=ignoredups
To remove duplicates from the entire history, use the following:
export HISTCONTROL=erasedups
You can also ask the history command not to remember a particular set of commands. For example, you may never want history to remember ‘rm -r *’. The trick is to export the following variables, and start your commands with a space, like ‘ rm -r *’ (there is a space before rm).
export HISTCONTROL=ignorespace
For better control, you can use the below example to remove few commands altogether.
export HISTIGNORE="rm:rm -r *"
To clear all your previous history, use
history -c
6. Word designators: Suppose I want to choose the n-th word from a history, I can use a saperator ‘:’. A : separates the event specification from the word designator. It may be omitted if the word designator begins with a ^, $, *, -, or %. Words are numbered from the beginning of the line, with the first word being denoted by 0 (zero). Words are inserted into the current line separated by single spaces. Let’s take examples:
To select nth word from the history, use:
$ ls -ltr a* -rw-r--r-- 1 ubuntu ubuntu 38 2011-07-31 09:16 abc.txt $ echo !ls:2 echo a* abc.txt
To select a range of words, use:
$ echo !ls:2-3 echo a* b* abc.txt bcd.txt
To select all the words, you can also use
$ ls a* b* abc.txt bcd.txt $ echo !ls:* echo a* b* abc.txt bcd.txt
7. Substitution: After you have chosen the words from the history, you can replace few old words with new words as s/old/new/. Substitution is separated from word designators again with ‘:’. For example:
$ ls a* abc.txt $ echo !ls:1:s/a/b echo b* bcd.txt
A :& can be used to repeat the previous substitution:
$ ls a* abc.txt $ echo !ls:1:s/a/b echo b* bcd.txt $ cat !ls:1:& cat b* how are you? i am fine how about you?