How would one parse the previous command in bash?


root$ ssh [email protected]
root$ echo !$ &>/tmp/foo.txt
root$ cat /tmp/foo.txt
[email protected]

Send just the ipaddress to foo.txt

I've attempted to used awk, but have not found success

#doesn't work
cat /tmp/foo.txt |awk '{print $2,$3,$4}' 

I've also attempted to parse out just the digits using sed

#doesn't work
sed 's/.//p' /tmp/foo.txt 
sed 's/[0-9]//p' /tmp/foo.txt

Considerations will always be a number between and
The user name foo can be any length
[email protected] is not necessarily the only parameter passed into ssh (eg.. ssh -l foo)


Further Clarification
The end goal will be to create a function in my .bashrc that will allow me to easily remove a conflicting ssh key.

root$ ssh [email protected]  
#some big error message warning about man in the middle attack
root$ ssh-keygen -R

6 Answers 6


With your original syntax:
$ cat /tmp/foo.txt | awk -F@ '{print $2}'


If you can use another syntax for the ssh command, it get's easier:

ssh -l foo 
echo !:3 

but this requires this exact syntax.

  • +1, This is a good idea. Very elegant. I'd prefer to not retrain myself to use the -l every time tough.
    – spuder
    Jul 22, 2013 at 18:38

You can use !! to access the previous command line so

echo !! | sed 's/.*@\(.*\).*/\1/' | awk '{print $1}'

may work for you e.g.

echo ssh [email protected] ls | ...

echo ssh -p 19111 [email protected] | ...

The only assumption here is that the ipaddress will be preceded by an @ and that there is a space or end of line after it.


When you had print output to a file, I will use Perl:

cat /tmp/foo.txt | \
perl -ne ' print $& if $_ =~ /(\d+)\.(\d+)\.(\d+)\.(\d+)/'

To find a numeric IP address from the previous ssh command:

echo $(grep -oP '\d+\.\d+\.\d+\.\d+' <<< "!ssh")

I don't see anything in the manual that would let you find "an argument matching a pattern" (http://www.gnu.org/software/bash/manual/bashref.html#History-Interaction)

Pretty sure you can't put !-style history expansions inside a function, but there's the fc command:

# return the IP address of the most recent ssh command
sship () { command grep -oP '\d+\.\d+\.\d+\.\d+' < <(fc -l ssh); }

This will not constrain you to have the ip address as a specific (e.g. the last) argument

ssh [email protected] hostname

There's no history expansion construct to break at @. However the last argument of the previous command is also available as the variable $_.

ssh-keygen -R "${_##*@}"

Note that this only works if the host name was the last argument of the previous command: it won't work if the previous command was e.g. ssh somehost ls. You can attempt parsing the output of fc -ln -1 to extract the first non-option argument.

Your goal strikes me as a rather bad idea. It is rare to need to remove an SSH host key — basically it should only happen if the machine has been reinstalled. If you need to do that often, something is wrong with your methodology, or perhaps with your network setup (make sure that your DHCP clients get reproducible IP addresses unless you're never ever going to connect to them from another machine).

  • Thanks for the input. Myself and others create and destroy dozens of openstack instances per week for testing. You can see additional details about why I get so many conflicting ssh keys on this question serverfault.com/questions/506864/…
    – spuder
    Jul 23, 2013 at 4:01

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .