Automatic interaction of shell with expect command

Time:2021-7-22

background

There are many scenarios in Linux script for remote operation, such as remote login SSH, remote copy SCP, file transfer SFTP and so on. The input of security password is involved in these commands. In normal use, it is necessary to manually input the password and accept security verification. In order to realize automatic remote operation, we can borrow the function of expect.

expect

The core of expect is splash, expect, send and set.

Splash calls the command to be executed

expectWaiting for the command prompt information to appear is to capture the prompt of user input
sendSend the value that needs interaction instead of the user’s manual input
setSet variable value
interactAfter the execution is completed, keep the interactive state, and give the control to the console. At this time, you can operate manually. If you don’t have this sentence, you will exit after login, instead of staying on the remote terminal.
expect eofThis must be added, corresponding to the splash, indicating that the capture terminal output information is terminated, similar to if… ENDIF

Expect scripts must end with interact or expect EOF, and expect EOF is usually enough for automated tasks.

Other settings

  • Set expect never to time outset timeout -1
  • Set the timeout of expect 300 seconds. If no expect content appears after 300 seconds, exitset timeout 300

Expect writing syntax

Expect uses TCL syntax

  • A tcl command consists of words separated by spaces. The first word is the command name, and the rest are the command parameters
    cmd arg arg arg
  • The $sign represents the value of the variable. In this case, the variable name is foo
    $foo
  • Square brackets execute a nested command. For example, if you want to pass the result of one command as an argument to another command, you use this symbol
    [cmd arg]
  • Double quotation marks a phrase as an argument to a command. The “$” symbol and square brackets are still interpreted in double quotation marks
    "some stuff"
  • Braces also mark a phrase as an argument to a command. However, other symbols are not interpreted within braces
    {some stuff}
  • Backslash is used to refer to special symbols. For example, n stands for newline. Backslash is also used to close the special meaning of “$” symbol, quotation mark, square bracket and brace

Examples

Login.exp is dedicated to remote login. The shortcut is as follows:login.exp "exclude" "${remote_ip}" "${remote_user}" "${remote_passwd}" "${remote_command}"

#!/usr/bin/expect -f
##########################################################
#Login and execute commands through SSH
#Parameter: 1. Use_ Type [check/execute]
#     2.SSHServerIp
#     3.SSHUser
#     4.SSHPassword
#5. Commandlist; [interval]
#Return value:
#0 success
#1. The number of parameters is incorrect
#2. The ssh server service is not opened
#3. The SSH user password is incorrect
#4 connection to ssh server timeout
##########################################################

proc usage {} {
    regsub ".*/" $::argv0 "" name
    send_user "Usage:\n"
    send_user "    $name Use_Type SSHServerIp SSHUser SSHPassword CommandList\n"
    exit 1
}
  
##Number of judgment parameters
if {[llength $argv] != 5} {
    usage
}

#Set variable value
set Use_Type [lindex $argv 0]
set SSHServerIp [lindex $argv 1]
set SSHUser [lindex $argv 2]
set SSHPassword [lindex $argv 3]
set CommandList [lindex $argv 4]

#spawn ping ${SSHServerIp} -w 5
#expect {
#    -nocase -re "100% packet loss" {
#        send_error "Ping ${SSHServerIp} is unreachable, Please check the IP address.\n"
#        exit 1
#    }
#}

set timeout 360
set resssh 0
#Define whether to enter yes when marking SSH connection
set inputYes 0
set ok_string LOGIN_SUCCESS
if {$Use_Type=="check"} {
    #Activate the SSH connection. If you need to enter yes to confirm, enter yes and set inputyes to 1. Otherwise, enter the SSH password
    spawn ssh ${SSHUser}@${SSHServerIp} "echo $ok_string"
} else {          
    spawn ssh ${SSHUser}@${SSHServerIp} "$CommandList"
}
expect {
    -nocase -re "yes/no" {
        send -- "yes\n"
        set inputYes 1
    }
    -nocase -re "assword: " {
        send -- "${SSHPassword}\n"
        set resssh 1
    }
   #-nocase -re "Last login: " { 
   #     send -- "${CommandList}\n"
   #}
    $ok_string {}
    -nocase -re "Connection refused" {
        send_error "SSH services at ${SSHServerIp} is not active.\n"
        exit 2
    }
    timeout {
        send_error "Connect to SSH server ${SSHUser}@${SSHServerIp} timeout(10s).\n"
        exit 4
    }
}

#If yes is entered, enter the SSH password
if {$inputYes==1} {
    expect {
        -nocase -re "assword: " {
            send -- "${SSHPassword}\n"
            set resssh 1
        }
    }
}

#If try again or password: prompt appears, it means that the user password entered is wrong and you can exit directly.
if {$resssh==1} {
    expect {
        -nocase -re "try again" {
            send_error "SSH user:${SSHUser} passwd error.\n"
            exit 3
        }
        -nocase -re "assword:" {
            send_error "SSH user:${SSHUser} passwd error.\n"
            exit 3
        }
        eof {}
    }
}
send_error -- "$expect_out(buffer)"
#-nocase -re "No such user" {
#        send_error "No such user.\n"
#        exit 5
#    }
#exit