2

How would one parse the previous command in bash?

Example:

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

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
[email protected] is not necessarily the only parameter passed into ssh (eg.. ssh 1.2.3.4 -l foo)

Resources

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 1.2.3.4 

    6 Answers 6

    5

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

    2
    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
    • +1, This is a good idea. Very elegant. I'd prefer to not retrain myself to use the -l every time tough.
      – spuder
      CommentedJul 22, 2013 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 [email protected] ls | ... 123.456.654.321 echo ssh -p 19111 [email protected] | ... 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 [email protected] 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).

          1
          • 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
            CommentedJul 23, 2013 at 4:01

          You must log in to answer this question.

          Start asking to get answers

          Find the answer to your question by asking.

          Ask question

          Explore related questions

          See similar questions with these tags.