Using if/else in expect script

2019-07-21 03:53发布

I recently updated and reformatted my /etc/hosts file and would like to run through every system (roughly 1000) to refresh my known_hosts file. I'm looking at using an expect script to send "yes" to the RSA fingerprint question. Simple enough. However, I know some of these systems are completely new to me and my password has not been set. This creates two possibilities:

  1. "yes" is sent to the RSA fingerprint question and I'm logged into the server. I'll then need to send an exit to close the connection before moving onto the next host. Or...

  2. "yes" is sent to the RSA fingerprint question and I'm presented with the prompts to update my password starting with the current and followed by the new password entered twice. The connection will automatically close after the password is updated moving onto the next host.

I think I have a basic grasp of the concept of "if/else" in expect, but I don't fully understand how to nest them, if there is a better way, or if I'm completely off-base to begin with.

This is what I have right now:

set file1 [open [lindex $argv 0] r]

set pw1 [exec cat /home/user/.pw1.txt]
set pw2 [exec cat /home/user/.pw2.txt]

while {[gets $file1 host] != -1} {

    puts $host
    spawn -noecho "ssh $host"
    expect {
        "continue connecting"{
            send "yes\r"
            expect {
                "current" {
                    send $pw2\r
                } "New password" {
                    send $pw1\r
                } "Retype new password" {
                    send $pw1\r
                }
            }
        expect "msnyder"
        send "exit\r"
    }
    interact
}

The file1 variable is the list of hosts to run the script against.

I know it isn't accurate because it errors on line 22. But, I have no idea what needs to be fixed.

标签: linux expect
2条回答
何必那么认真
2楼-- · 2019-07-21 04:21

You can probably avoid having the script run like a human and just spawn an expected to fail ssh connection which will automatically accept the host RSA key and not bother with prompting for a password; you can do that later for new systems where you need to initiate a password.

Temporarily try adding this to your ~/.ssh/config file until your script is finished:

Host *
  Protocol 2
  PasswordAuthentication 0
  StrictHostKeyChecking 'no'
  CheckHostIP 'no'
  UserKnownHostsFile ~/.ssh/known_hosts_new

Then when the new know_hosts_new file is loaded up, you can replace the default ~/.ssh/known_hosts and remove the UserKnownHostsFile line from your config.

查看更多
Viruses.
3楼-- · 2019-07-21 04:27

Two errors I spotted:

  1. missing close brace, probably for the "continue connecting" block
  2. missing space before the open brace of "continue connecting". Tcl (hence Expect) is very sensitive to whitespace as it is parsed into words before the commands are evaluated. For the very few gory details, see the 12 syntax rules of Tcl.

Your code might look like:

while {[gets $file1 host] != -1} {
    puts $host
    spawn -noecho "ssh $host"
    expect {
        "continue connecting" {
            send "yes\r"
            expect {
                "current" {
                    send -- $pw2\r
                    exp_continue
                } 
                "New password" {
                    send -- $pw1\r
                    exp_continue
                } 
                "Retype new password" {
                    send -- $pw1\r
                    exp_continue
                }
                msnyder
            }
            send "exit\r"
        }
    }
    interact
}

Notes:

  • exp_continue is used to "loop" back up to the expect statement: in this case, you will expect to see all of "current", "new" and "retype", so you don't want to bail out until you see your prompt.
  • get into the habit of typing send -- something. Without the double dash, you'll be surprised the day someone types in a password with a leading dash.
查看更多
登录 后发表回答