2

How would one parse the previous command in bash?

Example:

root$ ssh foo@1.2.3.4
root$ echo !$ &>/tmp/foo.txt
root$ cat /tmp/foo.txt
foo@1.2.3.4

Goal:
Send just the ipaddress 1.2.3.4 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
1.2.3.4 will always be a number between 0.0.0.0 and 255.255.255.255
The user name foo can be any length
foo@1.2.3.4 is not necessarily the only parameter passed into ssh (eg.. ssh 1.2.3.4 -l foo)

Resources
https://stackoverflow.com/questions/1733692/how-to-use-sed-awk-or-gawk-to-print-only-what-is-matched
https://stackoverflow.com/questions/2777579/sed-group-capturing
http://www.grymoire.com/Unix/Sed.html

Update
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 foo@1.2.3.4  
#some big error message warning about man in the middle attack
root$ ssh-keygen -R 1.2.3.4

migrated from serverfault.com Jul 22 '13 at 20:06

This question came from our site for system and network administrators.

5

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

1

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

ssh -l foo 1.2.3.4 
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 '13 at 18:38
0

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 user@123.456.654.321 ls | ...
123.456.654.321

echo ssh -p 19111 user@123.456.654.321 | ...
123.456.654.321

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.

0

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

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

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 user@1.2.3.4 hostname
0

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 '13 at 4:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.