Linux-expect用法
Expect是一个用来处理交互的命令。借助Expect,我们可以将交互过程写在一个脚本上,使之自动化完成。可以实现ssh远程连接别的机器,并且在上面执行相应的命令
Expect中常用最关键的四个命令:send,expect,spawn,interact。
send:用于向进程发送字符串,根据终端提示符是不是和expect的结果来传入,符合就传入
expect:从进程接收字符串,从spawn中接受;expect可以接收一个字符串参数,也可以接收正则表达式参数
spawn:启动新的进程
interact:允许用户交互
常见命令参数:
“\r”,表示回车
exp_continue,表示当问题不存在时继续回答下面的问题
expect eof ,表示问题回答完毕退出 expect 环境
interact,表示问题回答完毕留在交互界面
set NAME [ lindex $argv n ],定义变量
set timeout -1 设置超时方式为永远等待
set timeout 30 设置超时时间为30秒
[lindex $argv 0] 获取expect脚本的第1个参数
[lindex $argv 1] 获取expect脚本的第2个参数
expect "Hi\n"
send "hello here\n"
从标准输入中等到Hi和换行键后,向标准输出输出hello here
expect最常用的语法是来自tcl语言的模式-动作。这种语法极其灵活,下面我们就各种语法分别说明。
单一分支模式语法:
expect "hi" {send "You said hi"}
匹配到hi后,会输出"you said hi"
多分支模式语法:
expect "hi" { send "You said hi\n" } \
"hello" { send "Hello yourself\n" } \
"bye" { send "That was unexpected\n" }
匹配到hi,hello,bye任意一个字符串时,执行相应的输出。等同于如下写法:
expect {
"hi" { send "You said hi\n"}
"hello" { send "Hello yourself\n"}
"bye" { send "That was unexpected\n"}
}
set timeout -1
spawn ftp ftp.test.com //打开新的进程,该进程用户连接远程ftp服务器
expect "Name" //进程返回Name时
send "user\r" //向进程输入anonymous\r
expect "Password:" //进程返回Password:时
send "123456\r" //向进程输入don@libes.com\r
expect "ftp> " //进程返回ftp>时
send "binary\r" //向进程输入binary\r
expect "ftp> " //进程返回ftp>时
send "get test.tar.gz\r" //向进程输入get test.tar.gz\r
cat >> ssh.exp << 'EOF'
#!/usr/bin/expect
set IP [ lindex $argv 0 ] #设置变量也就是192.168.23.144
set PASSWD [ lindex $argv 1 ] #设置变量也就是密码****
spawn ssh root@$IP #开启一个新进程连接某台主机
expect {
"yes/no" { send "yes\r" ; exp_continue } #exp_continue,表示当问题不存在时继续回答下面的问题
"password" { send "$PASSWD\r" }
}
interact #表示问题回答完毕留在交互界面
EOF
expect ssh.exp 192.168.23.144 *****
#!/usr/bin/expect
spawn ssh root@192.168.23.144 #开启一个新进程,ssh连接一个机器
expect "*password:" #上面执行完之后,会出现**password: ,这里面*是通配符
send "123\r" #当终端提示符出现和expect中字符一样,就自动输入123,并且回车
expect "*#"
interact # 表示问题回答完毕留在交互界面
[root@k8s-master 20210728]# cat ssh.exp
#!/usr/bin/expect
set IP [ lindex $argv 0 ]
set PASSWD [ lindex $argv 1 ]
spawn ssh root@$IP
expect {
"yes/no" { send "yes\r" ; exp_continue }
"password" { send "$PASSWD\r" }
}
send "pwd\n"
expect "ren" ###有没有这个都会执行send "ls\n"当expect和send没有在一行的时候,没有交互
send "ls\n"
#interact #留在当前ssh登录的环境信息
expect eof #退出当前ssh登录的环境信息,退到当前执行脚本的机器
可见expect 和send的结合是在交互界面上,同一行的情况下比如password: 要输入密码了,expect
expect "*#" {send "echo rens\n"} 当匹配到[root@docker01 ~]# echo rens就会输入echo rencs\n
expect "rencs" {send "echo rens\n"} 因为匹配不到rencs 在[root@docker01 ~]# 中就不会输入echo rencs\n
总结:
spawn ssh -o StrictHostKeyChecking=no $username@$ip
expect "password:"
send "$passwd\r"
expect "Enter selection or (0) to quit:"
send "r"
expect "Do you really want to start the Console Redirection (yes/no)?"
send "yes"
send "\r"
expect "login:"
上面那种情况,都在一个任务下:就可以一行expect;一行send
[root@k8s-master 20210728]#
password: $passwd
Enter selection or (0) to quit: r
Do you really want to start the Console Redirection (yes/no)? yes r
……
[root@k8s-master 20210728]#
expect "*#" {send "echo rens\n"} 因为匹配到#在[root@docker01 ~]# 就会输入echo rencs\n
expect "rencs" {send "echo rens\n"} 因为匹配不到rencs 在[root@docker01 ~]# 中就不会输入echo rencs\n
send "pwd\n"
expect "ren" ###有没有这个都会执行send "ls\n"当expect和send没有在一个任务的的时候,没有交互和匹配
send "ls\n"
send "pwd\n"
#expect "root"
expect "erfrie"
#expect "rencs" {send "echo rens\n"}
send "ls\n"
expect "config.yaml" #有没有这个都会执行下面的uname
send "uname -n\n"
expect "centos" ##有没有这个都会执行下面的uname,因为和下面的不是在一个任务当中,不存在匹配就执行
send "uname -r\n"
#interact
expect eof