How to return from shell 'read' command pa

2019-08-11 19:48发布

问题:

I am really new to using expect, and a bit confused regarding passing commands to an expect script, so please bear with me... I have searched numerous forums, but cannot seem to find an example of an expect script that uses the read command to get user input.

In my Korn shell script, I call an expect script (expectssh.exp) to ssh login to another host and get user input regarding that host's network configuration (network interface card number and subnet mask information). I pass four arguments to the expect script: the remote host ip address, the username, the password, and the list of commands to run. My expect script is below:

#!/usr/bin/expect
# Usage: expectssh <host> <ssh user> <ssh password> <script>

set timeout 60
set prompt "(%|#|\\$) $"
set commands [lindex $argv 3];

spawn ssh [lindex $argv 1]@[lindex $argv 0]

expect {
"*assword:" { 
send -- "[lindex $argv 2]\r" 
expect -re "$prompt"
send -- "$commands\r" 
}

"you sure you want to continue connecting" {
send -- "yes\r"
expect "*assword:"
send -- "[lindex $argv 2]\r"
expect -re "$prompt"
send -- "$commands\r" 
}

timeout {
exit }
}

The script runs well, except that when it gets to the 'read' command, the script does not continue or exit after the user presses enter. It just hangs.

The commands I pass to the expect script and its call are as follows:

SCRIPT='hostname > response.txt;netstat -rn;read net_card?"What is the network interface card number?   " >> response.txt; read net_mask?"What is the subnet mask? " >> response.txt'

/usr/bin/expect ./expectssh.exp $hostip $usr $pswd "$SCRIPT"

Any suggestions on how I can pass the read command through my expect script without it hanging?

On a side note because I know it will come up - I am not allowed to do key-based automatic SSH login. I have to prompt for a username and password, which is done from the Korn shell script that calls this expect script.

Thanks for any suggestions and help you can provide!

回答1:

For anyone interested, I was able to get the read command to work for user input by doing a few things:

(1) Putting it within an -re $prompt block instead of appending send -- "$commands\r" after the password entry.

(2) Hard coding the commands into the script rather than passing them in.

(3) Following the command with an interact statement so that the next send command isn't entered before the user responds.

My expect block now looks like this:

expect {
    -re "(.*)assword:" { 
        send -s "$pswd\r" 
        exp_continue
    }
    "denied, please try again" {
        send_user "Invalid password or account.\n"
        exit 5
    }
    "incorrect" {
        send_user "Invalid password or account.\n"
        exit 5
    }
    "you sure you want to continue connecting" {
        send -s "yes\r"
        exp_continue
    }
    -re $prompt {
        set timeout -1
        send -- "hostname > partnerinit\r"
        expect -exact "hostname > partnerinit\r"
        send -s "netstat -rn\r"
        expect -re "$prompt"
        send -- "read n_card?'Enter the network interface card number for this server (i.e. eth0):  '\r"
        interact "\r" return
        send -- "\r"
        send -- "echo \$n_card >> partnerinit\r"
        send -- "msk=\$(cat /etc/sysconfig/network-scripts/ifcfg-\$n_card | grep NETMASK)\r"
        send -- "msk=\$(echo \${msk#NETMASK=})\r"
        send -- "echo \$msk >> partnerinit\r"
        send -- "cat partnerinit\r"
        set retval 0
    }
    timeout {
        send_user "Connection to host $host timed out.\n"
        exit 10
    }
    eof {
        send_user "Connection to host $host failed.\n"
        exit 1
    }
}

I also updated the script to automatically determine the subnet mask based on the network interface card number entered by the user. It was brought to my attention that finding the network interface card number would be very difficult to automate in the case of a box that has multiple interface cards. Better to start small and have the user enter it and fine-tune/automate it later once the overall script is working.

Now I'm working on modifying this to scp my partnerinit file back to my local host and to return meaningful exit statuses from each of the expect conditions.