Linux expect send weird constructions

2019-06-12 16:43发布

问题:

I am trying to figure out how expect working. AFAIK the expect script consists of "expect" and "send" statements. So for each approporiate "expect" statement which appears on screen the "send" statement is called. Also the command "interact" means that controlling is passed back to user and he is able to interact with the terminal. Correct me if I am wrong. Those two statements works like a charm.

1st:

#!/usr/bin/expect
spawn ssh -q localhost;

# Handles following message: "Are you sure you want to continue connecting (yes/no)?"
expect "yes";
send "yes\r";
interact;

2nd:

#!/usr/bin/expect
spawn ssh -q localhost;

# Handles following message: "pista@localhost's password:" 
expect "assword";
send "password\r";
interact;

I've found on internet that something like following code should combine those two examples into one:

#!/usr/bin/expect
spawn ssh -q localhost "uname -a";
expect {
    "*yes/no*" { send "yes\r" ; exp_continue }
    "*assword:" { send "password\r"; interact }
}

But this example exits immediatelly after sucesfull login (seems like "interact" is not workig here, see output bellow)

[pista@HP-PC .ssh]$ ./fin.exp
spawn ssh -q localhost uname -a
pista@localhost's password: 
Linux HP-PC 3.6.6-1.fc16.x86_64 #1 SMP Mon Nov 5 16:56:43 UTC 2012 x86_64 x86_64 x86_64 GNU/Linux
[pista@HP-PC .ssh]$ set | grep SHLV
SHLVL=2

Three questions:

  1. What those weird expect syntax mean, only possible explaination to me is that there is no emphasis on patterns order in this "big" expect ?
  2. Can you please clarify what is exactly exp_continue doing, seems to me like "goto" statement to expect which invoked this ?
  3. Why is not interact working here ?

Many thanks

回答1:

1. This syntax means that you use consecutive expect statements, it's easier. For example, this will try SSH or telnet if SSH fails

#!/usr/bin/expect
set remote_server [lrange $argv 0 0]
set timeout 10
spawn ssh -M username@$remote_server
while 1 {
  expect {
    "no)?"      {send "yes\r"}
    "denied" {
                log_file /var/log/expect_msg.log
                send_log "Can't login to $remote_server. Check username and password\n";
                exit 1
             }
    "telnet:" {
                log_file /var/log/expect_msg.log
                send_log "Can't connect to $remote_server via SSH or Telnet. Something went definitely wrong\n";
                exit 2
              }
    "failed" {
                log_file /var/log/expect_msg.log
                send_log "Host $remote_server exists. Check ssh_hosts file\n";
                exit 3
             }
    timeout {
                log_file /var/log/expect_msg.log
                send_log "Timeout problem. Host $remote_server doesn't respond\n";
                exit 4
            }
    "refused" {
                log_file /var/log/expect_msg.log
                send_log "Host $remote_server refused to SSH. That is insecure.\n"
                log_file
                spawn telnet $remote_server
              }
    "sername:" {send "username\r"}
    "assword:" {send "password\r"}
    "#"        {break}
  }
}

2. exp_continue is telling expect to "continue to expect", that is to continue with the event processing. Without this instruction your expect { ... } block will stop. In the example above it is the line:

"#" {break}

First it breaks from the while loop, and then without exp_continue it stops executing expect { ... } block and going for the next instructions (not shown in the example above).

3. You have an error in your code. I've slightly modified your code, to make it work.

#!/usr/bin/expect
spawn ssh -q localhost
expect {
    "*yes/no*" { send "yes\r" ; exp_continue }
    "*assword:" { send "password\r"; exp_continue;}
    "~" {send "uname -a\r"; interact;}
}


标签: expect