home | O'Reilly's CD bookshelfs | FreeBSD | Linux | Cisco | Cisco Exam  


UNIX Power Tools

UNIX Power ToolsSearch this book
Previous: 11.6 Using !$ for Safety with Wildcards Chapter 11
The Lessons of History
Next: 11.8 Repeating a Cycle of Commands
 

11.7 History Substitutions

[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. -JP]

The exclamation point ( ! ) is the C shell's default ( 11.15 ) history substitution character. (It's used in bash , too.) This allows you to recall previously entered commands and re-execute them without retyping. The number of commands saved is up to you. To set this number, put a line in your shell setup file ( 2.2 ) like this:

set history=40   
...C shell


HISTSIZE=40   
...bash, ksh

This means that the C shell will save the last 40 commands. To list out these 40 commands use:

% 

history

To see just the last ten commands in csh or bash , use history 10 . In the C shell, you can also list out the commands in reverse with history -r .

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 used mostly to select arguments from the command line in aliases ( 10.3 ) . Here they are:

  • !! repeats the last command.

  • !: repeats the last command. This form is used if you want to add a modifier ( 9.6 ) like:

    % 
    
    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 . ( 7.2 )

  • !! & 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 ( 25.3 ) 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 ( 9.6 ) :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:

    % 
    
    cat fn fn1 fn2
    
    
           ...
    % 
    
    more !:3
    
    
    more fn2
           ...

    gives the third argument.

  • !:2-4 gives the second through the fourth argument, or 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, or 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 ( 26.4 ) , !^ 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.

  • !* 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'

    will pipe the output of cat -v ( 25.7 ) command through more . The backslash ( \ ) has to be there to hide the history character, ! , until the alias is used-see article 10.3 for more information.

  • !:2* gives the second through the last arguments:

    % 
    
    echo 1 2 3 4 5
    
    
    1 2 3 4 5
    % 
    
    echo !:2*
    
    
    echo 2 3 4 5
    2 3 4 5

  • !:2- 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:

    % 
    
    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 ( 11.3 , 11.5 ) command. In the case of:

    % 
    
    echo xxyyzzxx
    
    
    xxyyzzxx
    % 
    
    ^xx^ab
    
    
    echo abyyzzxx
    abyyzzxx

    it replaced the 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 the colons ( : ) [good when the word you're trying to edit contains a slash- JP ]. 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 ( 26.3 ) . You must type the actual string you are looking for.

    Also, the example above only replaces 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.

    Or you could have done:

    % 
    
    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 that case, 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 .

    [A "global" substitution works just once per word:

    % 
    
    echo xyzzy
    
    
    xyzzy
    % 
    
    !!:gs/y/p/
    
    
    echo xpzzy
    xpzzy

    The substitution above changed only the first y . -TC ]

- DR


Previous: 11.6 Using !$ for Safety with Wildcards UNIX Power Tools Next: 11.8 Repeating a Cycle of Commands
11.6 Using !$ for Safety with Wildcards Book Index 11.8 Repeating a Cycle of Commands

The UNIX CD Bookshelf Navigation The UNIX CD BookshelfUNIX Power ToolsUNIX in a NutshellLearning the vi Editorsed & awkLearning the Korn ShellLearning the UNIX Operating System