views:

51

answers:

2

I couldn't find an answer for this exact problem, so I'll ask it.

I'm working in Cygwin and want to reference previous commands using !n notation, e.g., if command 5 was which ls, then !5 runs the same command.

The problem is when trying to do substitution, so running:

!5:s/which \([a-z]\)/\1/

should just run ls, or whatever the argument was for which for command number 5.

I've tried several ways of doing this kind of substitution and get the same error:

bash: :s/which \([a-z]*\)/\1/: substitution failed
+1  A: 

As far as I can tell the s/old/new/ history substitution syntax only does simple string substitution; it does not support full regexes. Here's what man bash has to say:

s/old/new/

Substitute new for the first occurrence of old in the event line. Any delimiter can be used in place of /. The final delimiter is optional if it is the last character of the event line. The delimiter may be quoted in old and new with a single backslash. If & appears in new, it is replaced by old. A single backslash will quote the &. If old is null, it is set to the last old substituted, or, if no previous history substitutions took place, the last string in a !?string[?] search.

Never fear, though. There are in fact easier ways to accomplish what you are trying to do:

  1. !$ evaluates to the last argument of the previous command:

    # ls /etc/passwd
    /etc/passwd
    # vim !$
    vim /etc/passwd
    
  2. !5:$ evaluates to the last argument of command #5:

    # history
    ...
    5: which ls
    ...
    # !5:$
    ls
    
  3. You can also use Alt+. to perform an immediate substitution equivalent to !$. Alt+. is one of the best bash tricks I know.

John Kugelman
A: 

This worked for me using Bash in Cygwin (note that my which ls command was number 501 in my history list; not 5 like yours):

$(!501 | sed 's/which \([a-z]\)/\1/')

You could also do it this way (which is shorter/cleaner):

$(!501 | sed 's/which //')

DevNull
Thanks for the help everyone
Ira