Tcl & Expect

1. 流程

  1. 运行一个Expect程序

  2. spawn寄生目标程序,接管目标程序的输入输出

  3. expect判断目标程序的输出,做相应逻辑判断

  4. send用来向目标程序输入

  5. interact将控制权交给用户

2. spawn

寄生目标程序,接管目标程序的输入输出,这通常都是expect脚本的第一步,默认情况下,spawn会回显命令名称和参数,可以用-noecho参数来让它不回显

3. send

Characters are sent immediately although programs with line-buffered input will not read the characters until a return character is sent. A return character is denoted "\r".

向目标程序输入,字符直接发送给程序,但要注意,行缓冲输入的程序直到收到一个return字符才会接收这些输入字符,return字符用"\r"表示

  1. send_user 输入到 stdout,一般做提示用

4. expect

匹配被寄生的程序的输出与模式,如果匹配上,执行相应动作。匹配成功或超时或遇到文件尾时都会返回

一旦匹配上,则开始执行对应的语句。默认情况下,模式采用Tcl语言的string match命令匹配

模式中可用的特殊符号:

符号

含义

*

匹配任何字符串,包括空null字符串

?

匹配任意单个字符

[chars]

匹配chars中指定的字符集合,比如[A-Za-z]匹配所有字母,再比如[abc]匹配abc三个字符中的任意

\x

匹配字符x,提供了一种防止特殊字符转义的匹配方法,比如\\可以匹配反斜杠这个字符,\?可以匹配问号,\*可以匹配*

可以加上-re参数指定使用正则表达式匹配

4.1. exp_continue

重新调用expect

4.2. expect_user

跟expect一样,不过它从标准输入读数据,默认情况下,读取工作在cooked模式下,所以,必须敲回车才能让expect看到数据

4.3. expect_before & expect_after

比如有下面的例子:

expect {
    "login:" {send "$user\r"}
    eof eofproc
}
expect {
    "password:" {send "$password\r"}
    eof eofproc
}
expect {
    "$prompt" {send "$command\r"}
    eof eofproc
}

可以用expect_after

expect_after eof eofproc
expect "login:"    {send "$user\r"}
expect "password:" {send "$password\r"}
expect "$prompt"   {send "$command\r"}

最近的expect_after都会加到expect里组成一个新的执行体,expect_after和expect_before的区别在于顺序不同,当expect和expect_after或expect_before匹配同一个模式时,expect_after会后于expect执行,而expect_before会先于expect执行

4.4. expect_out

expect_out(0, string)

expect匹配的字符串

5. interact

6. 自动生成Expect脚本

7. cooked模式和raw模式

cooked模式下会对特殊字符做预处理,如退格、删除、Control-C和Control-D等。raw模式不会做预处理,数据被原样传递给应用程序。

比如,在cooked模式下,输入ABC<Backspace>D,最终传给程序的是ABD。而在raw模式下,程序收到的是ABC加一个退格符再加一个D

8. Tcl

Tcl是一种工具命令语言,可参考资料:http://tmml.sourceforge.net/doc/tcl/

常用语法

  1. 方括号[],相当于sh编程中的`符号,被括起来的语句会先执行并返回结果

  2. proc 子程序(函数)

  3. set 设置变量

  4. info exists varName 变量是否存在

  5. lindex 取数组元素

  6. string equals 比较string是否相等

9. case

#!/usr/bin/expect -f

if { $argc >= 1 } {
    set target_host [lindex $argv 0]
}

if { $argc >= 2 } {
    set target_dir [lindex $argv 1]
} else {
    set target_dir ""
}

set timeout -1
set bridge_host "jumper.abc.com"
set username "xiaomi"
set password "1234567"

proc go_target { target_host target_dir } {
    if { [info exists target_host] } {
        send "ssh ${target_host}\r"
            expect {
                "$*" { send "sudo -uabc -i\r" }
            }
        if { ![string equal ${target_dir} ""] } {
            expect {
                "*abc" {
                    send "cd ${target_dir}\r"
                }
            }
        }
        interact
    }
}
spawn ssh "${username}@${bridge_host}"
expect {
    "Jumper*" { go_target $target_host $target_dir }
    "*Password*" {
        send_user "please enter verification code (6 digit):"
            expect_user -re "(.*)\n"
            set veri_code $expect_out(0,string)
            send "${password}${veri_code}\n"
                expect {
                    "xiaomi@Jumper" { go_target $target_host $target_dir }
                }
    }
}

10. 参考资料

http://wiki.tcl.tk/4385

https://www.safaribooksonline.com/library/view/exploring-expect/9781565920903/ch11s10.html#

http://www.tcl.tk/man/expect5.31/expect.1.html

https://en.wikipedia.org/wiki/Cooked_mode

https://www.tcl.tk/man/tcl8.5/tutorial/Tcl5.html

猜你喜欢

转载自blog.csdn.net/xiaocszn/article/details/81709405
TCL
今日推荐