为什么使用spawn expect …
很多时候,指令的执行是需要交互的,比如下面这个命令大家一定很熟悉:
ssh-keygen -t rsa
# 以及
ssh-copy-id -i /home/xxx/.ssh/id_rsa.pub $username@$host_name
这里需要按三次回车键,或输入yes/no
,以及密码
才可以.当然,还是那句话单点操作随意,如果一项工作重复次数超过2次,那么我们就应该用脚本来管理它,比如我们要在一个集群规模的每个节点都进行上面的操作,那真的是会很累很累…
expect
expect是一款免费的工具,可以实现自动的交互式任务,无需人工干预.
它可以根据程序的提示信息,来模拟标准输入,提供给程序,以此来实现自动化交互执行的目的.
yum provides expect
# 或直接安装
yum install -y expect
expect命令
命令 | 作用 |
---|---|
spawn | 启动一个新的进程,用来执行后面所接的COMMAND |
expect | 期待从进程中获取的内容 |
send | 向进程发送内容 |
set timeout n | 设置超时时间,单位:秒 ,超过n秒则不再继续等待进程的内容返回 |
interact | 是否保留交互状态 |
命令演示
expect脚本文件的头信息与bash不同,这里需要注意
在这里强烈建议大家养成脚本注释的习惯,日后真的非常有用.
#!/usr/bin/expect
# Program:
# run the basic test of expect
# 2020/01/19 Shuu First release
spawn ssh test
expect "yes/no"
send "yes\r"
expect "password*"
send "test\r"
expect eof
上面的例子,我创建了一个test用户,密码也是test,来进行测试.
执行之后虽然命令提示符会显示test@xxxxxx
但是执行whoami命令后,会发生改变,而且执行结果并不是test用户.
那么如果想继续留在test用户下进行操作该怎么办呢?interact
的作用来了
#!/usr/bin/expect
# Program:
# run the basic test of expect
# 2020/01/19 Shuu First release
spawn ssh test
expect "yes/no"
send "yes\r"
expect "password*"
send "test\r"
interact
仅修改最后一行的expect eof为interact即可.将.ssh目录删掉,再次运行
rm -rf ~/.ssh
上面的内容还可以用另一种方式来书写:
Pattern—— Action:模式和动作,模式可以有多种,每匹配到一种模式进行相应的动作.
#!/usr/bin/expect
# Program:
# run the basic test of expect
# 2020/01/19 Shuu First release
spawn ssh test
expect {
"yes/no" {send "yes\r";exp_continue}
"password*" {send "test\r"}
}
expect eof
# or
# interact
exp_continue
,表示继续进行余下的模式匹配,除最后一个一般都要加,否则没必要写那么多Pattern不是吗.
在shell脚本中使用expect
由于expect与bash不同,(从表头就能看出
),所以在shell脚本中是不能直接使用spawn ... expect
的.
具体写法如下:
#!/bin/bash
# Program:
# details
# yyyy/MM/dd Author release
/usr/bin/expect <<EOF
spawn ssh-copy-id -i /home/hadoop/.ssh/id_rsa.pub $username@$host_name
expect {
"yes/no" {send "yes\r";exp_continue}
"password" {send "$password\r"}
}
expect eof
EOF
这里的/usr/bin/expect
会进入expect命令行交互模式
而后面的 <<EOF
表示知道接收到EOF
字符为止,一直接收输入内容,当接收到EOF
字符时,结束本次expect操作.
!!!这里是个坑
重要的事情说三遍:
EOF
前后一定不能有空格
!
EOF
前后一定不能有空格
!
EOF
前后一定不能有空格
!
所以,对代码缩进格式有着强迫症的同学要注意啦!!!
最后一行那个EOF一定要在起始位置,不能有空格!!!
</article>