abhijeet pathak
abhijeet pathak

Reputation: 126

Using nested spawn method in expect scripts

I have written following expect script:

/usr/bin/expect<<EOF
set SERVER_HOSTNAME "$env(SERVER_HOSTNAME)"

set USERNAME "$env(USERNAME)"
set PASSWORD "$env(PASSWORD)"

set timeout -1

spawn ssh "$USERNAME@$SERVER_HOSTNAME"
expect  {
        "Host key verification failed." { spawn ssh-keygen -R "$SERVER_HOSTNAME"; expect "known_hosts.old"; send_user "Updated host key details."; exp_continue}
        "continue connecting (yes/no)" { send "yes\r"; expect "Permanently added"; exp_continue}
        "assword:" { send_user "Keygen details are correctly mapped for this server\n"}
        }
EOF

Here I want that if the host key of a server can't be verified while spawing "ssh" process, then the nested spawn process "ssh-keygen -R" should remove old key. Then the "ssh" process should try to connect again so that new key can be added corresponding to that server.

But here, after the execution of:

send_user "Updated host key details."

method, expect process is exiting out from this script.

I know the alternative can be to divide this expect call into two steps, as follows:

 /usr/bin/expect<<EOF
set SERVER_HOSTNAME "$env(SERVER_HOSTNAME)"

set USERNAME "$env(USERNAME)"
set PASSWORD "$env(PASSWORD)"

set timeout -1

spawn ssh "$USERNAME@$SERVER_HOSTNAME"
expect  {
        "Host key verification failed." { spawn ssh-keygen -R "$SERVER_HOSTNAME"; expect "known_hosts.old"; send_user "Updated host key details."; exp_continue}            
        "continue connecting (yes/no)" { send "yes\r"; expect "Permanently added"; exp_continue}
       "assword:" { send_user "Keygen details are correctly mapped for this server\n"}
        }


spawn ssh "$USERNAME@$SERVER_HOSTNAME"
expect  {           
        "continue connecting (yes/no)" { send "yes\r"; expect "Permanently added"; exp_continue}
        "assword:" { send_user "Keygen details are correctly mapped for this server\n"}
        }

EOF    

But do we have a way to execute this expect call in one go. In nutshell, I want to know, can we do the nesting of spawn process?

Upvotes: 0

Views: 3592

Answers (1)

glenn jackman
glenn jackman

Reputation: 246774

Whitespace goes a long way toward maintainable code: you don't need to squish so many commands per line.

spawn ssh "$USERNAME@$SERVER_HOSTNAME"
expect {
    "Host key verification failed." {
        spawn ssh-keygen -R "$SERVER_HOSTNAME"
        expect "known_hosts.old"
        send_user "Updated host key details."
        exp_continue
    }
    "continue connecting (yes/no)" {
        send "yes\r"
        expect "Permanently added"
        exp_continue
    }
    "assword:" { 
        send_user "Keygen details are correctly mapped for this server\n"
    }
}

I this case, you don't need to interact with ssh-keygen, so use exec to simply call it

    "Host key verification failed." {
        exec ssh-keygen -R "$SERVER_HOSTNAME"
        puts "Updated host key details."
        exp_continue
    }

If you need to spawn something and interact with it, you need to know that there is an implicit variable, spawn_id, created by spawn, and used by expect and send. You'll need to save the spawn_id of the current process before you spawn any other process. For example:

spawn process1
set ids(1) $spawn_id
expect -i $ids(1) "some pattern"
send -i $ids(1) "some string\r"

spawn process2
set ids(2) $spawn_id
expect -i $ids(2) "some pattern from process2"
send -i $ids(2) "some string to process2\r"

Upvotes: 1

Related Questions