Although most of the examples here use echo to demonstrate clearly just what is going on, you'll normally use history with other Unix commands.
The exclamation point (!
) is the default (Section 30.15) history substitution
character. This allows you to recall previously entered commands and re-execute
them without retyping. To use the !
in a
command line, you have several choices. Some of the following examples are more
of a headache than they may be worth, but they are also used to select arguments from the command line in aliases
(Section 29.3):
!:
repeats the last command. This
form is used if you want to add a modifier (Section
28.5) like the following:
%echo xy
xy %!:s/xy/yx
echo yx yx
The second !
was left out.
!so
repeats the last command that
starts with so
.
!?fn?
repeats the last command that
has fn
anywhere in it. The string
could be found in an argument or in the command name. This is opposed to
!fn
, in which !fn
must be in a command name. (The last
?
need not be there. Thus
!?fn
means the same
thing.)
!34
executes command number 34. You
can find the appropriate history number when you list your history using
the history command, or by putting the history number in your prompt
(Section 4.3).
!! &
adds an ampersand
(&
) to the end of the last
command, which executes it and places it into the background. You can
add anything to the end of a previous command. For example:
%cat -v foo
... %!! | more
cat -v foo | more ...
In this case the shell will repeat the command to be executed and run it, adding the pipe through the more pager. Another common usage is:
%cat -v foo
... %!! > out
cat -v foo > out
which returns the command but redirects the output into a file.
!:0
selects only the command name,
rather than the entire command line.
%/usr/bin/grep Ah fn1
... %!:0 Bh fn2
/usr/bin/grep Bh fn2
Note that as an operator (Section 28.5,), :0
can be
appended to these history substitutions as well. For example, !!:0
will give the last command name, and
a colon followed by any number will give the corresponding argument. For
example, !:3
gives the third
argument:
%cat fn fn1 fn2
... %more !:3
more fn2 ...
!:2-4
gives the second through the
fourth argument; use any numbers you choose:
%echo 1 2 3 4 5
1 2 3 4 5 %echo !:2-4
echo 2 3 4 2 3 4
!:-3
gives zero through the third
argument; use any number you wish:
%echo 1 2 3 4
1 2 3 4 %echo !:-3
echo echo 1 2 3 echo 1 2 3
!^
gives the first argument of the previous command. This is the same as
!:1
. Remember that just as the
^
(caret) is the
beginning-of-line anchor in regular
expressions (Section
32.5), !^
gives the
beginning history argument.
%cat fn fn1 fn2
... %more !^
more fn ...
!$
gives the last argument of the last command. In the same way that
$
(dollar sign) is the
end-of-line anchor in regular expressions, !$
gives the ending history argument. Thus:
%cat fn
... %more !$
more fn ...
The new command (more
) is given the
last argument of the previous command. This is also handy for pulling
the last argument from earlier commands, which is typically a filename.
To get the last argument from the previous vi command, for example, you'd use !vi:$
. So you could type lpr !vi:$
to print the last file you
edited with vi.
!*
is shorthand for the first through the
last argument. This is used a lot in aliases:
%echo 1 2 3 4 5
1 2 3 4 5 %echo !*
echo 1 2 3 4 5 1 2 3 4 5
In an alias:
alias vcat 'cat -v \!* | more'
This alias will pipe the output of cat
-v (Section
12.4) command through more. The backslash (\
)
has to be there to hide the history character, !
, until the alias is used — see Section 29.3 for more
information.
!:2*
gives the second through the
last arguments; use any number you wish:
%echo 1 2 3 4 5
1 2 3 4 5 %echo !:2*
echo 2 3 4 5 2 3 4 5
!:2-
is like 2*
but the last argument is
dropped:
%echo 1 2 3 4 5
1 2 3 4 5 %echo !:2-
echo 2 3 4 2 3 4
!?fn?%
gives the first word found
that has fn
in it:
%sort fn1 fn2 fn3
... %echo !?fn?%
echo fn1 fn1
That found the fn
in fn1
. You can get wilder with:
%echo 1 2 3 4 5
1 2 3 4 5 %echo !?ec?^
echo 1 1
That selected the command that had ec
in it, and the caret (^
) said to give the first argument of that command. You
can also do something like this:
%echo fn fn1 fn2
fn fn1 fn2 %echo !?fn1?^ !$
echo fn fn2 fn fn2
That cryptic command told the shell to look for a command that had
fn1
in it (!?fn1?
), and gave the first argument of
that command (^
). Then it gave the
last argument (!$
).
^xy^yx
is the
shorthand substitution (Section 30.3, Section 30.5) command. In the
case of:
%echo xxyyzzxx
xxyyzzxx %^xx^ab
echo abyyzzxx abyyzzxx
it replaced the first set of characters xx
with ab
. This makes
editing the previous command much easier.
!!:s/xx/ab/
is doing the same thing
as the previous example, but it is using the substitute command instead of the
^
. This works for any previous
command, as in:
%more afile bfile
... %echo xy
xy %!m:s/b/c/
more afile cfile
You do not have to use the slashes (/
); any character can act as a delimiter.
% !!:s:xy:yx
There we used colons (:), good when the characters you're trying to
edit contain a slash. If you want to add more to the replacement, use
&
to "replay it" and then add
on whatever you like:
%echo xy
xy %!!:s/xy/&yx
echo xyyx xyyx
The &
in the replacement part
said to give what the search part found, which was the xy
characters.
The search part, or left side, cannot include metacharacters (Section 32.3). You must type the actual string you are looking for.
Also, the example above replaces only the first occurrence of xy
. To replace them all, use
g:
%echo xy xy xy xy
xy xy xy xy %!!:s/xy/yx/
echo yx xy xy xy yx xy xy xy %!!:gs/xy/yx/
echo yx yx yx yx yx yx yx yx
The g command in this case meant "do all the
xy
s." And oddly enough, the
g has to come before the s
command. This may seem odd to those of you familiar with vi, so be careful.
Or you could have done this:
%echo xy xy xy xy
xy xy xy xy %!!:s/xy/yx/
echo yx xy xy xy yx xy xy xy %!!:g&
echo yx yx yx yx yx yx yx yx
In this example, we told the shell to globally (:g
) replace every matched string
from the last command with the last substitution (&
). Without the g
command, the shells would have replaced just one more xy
with yx
.
— DR