[Linux] expect用法举例

expect有助于自动化脚本中的交互过程的自动输入,例如远程登录需要输入确认信息、密码,安装脚本需要输入确认信息、用户名、密码、选择配置选项等等。

expect内部命令中的expect可以匹配一个给定的字符串,匹配上了可以再使用send命令返回一个字符串。

[例1] 使用"-c"选项,从命令行执行expect脚本

[root@xxx test]# expect -c 'expect "\n" {send "pressed enter\n"}'

pressed enter
[root@xxx test]# 
[root@xxx test]# expect -c 'expect "hi" {send "You said hi\n"}'
hi
You said hi
[root@xxx test]# expect -c 'expect "hi" {send "You said hi\n"}'
high
You said hi
[root@xxx test]#

再看一个ssh登录的例子,

[例2-1] ssh登录主机,test.exp内容如下(主机名和密码写在脚本中,执行完成后退出)

#!/usr/bin/expect

set ipaddr "localhost"
set passwd "iampasswd"

spawn ssh root@$ipaddr

expect {
"yes/no" { send "yes\r"; exp_continue}
"password:" { send "$passwd\r" }
}

expect "]# "
send "cd /tmp/test;touch a.txt\r"

send "exit\r"

expect eof
exit

执行结果:

[root@xxx test]# ./test.exp
spawn ssh root@localhost
root@localhost's password:
Last login: Wed Mar  4 16:07:11 2020 from localhost
[root@xxx ~]# cd /tmp/test;touch a.txt
[root@xxx test]# exit
logout
Connection to localhost closed.
[root@xxx test]#

检查当前路径下已创建a.txt

[root@xxx test]# ls -l
total 4
-rw-r--r-- 1 root root   0 Mar  4 16:09 a.txt
-rwxr-xr-x 1 root root 274 Mar  4 16:09 test.exp
[root@xxx test]#

说明:

1. #!/usr/bin/expect 
首行告诉操作系统脚本里的代码使用那一个shell来执行。这里的expect其实和linux下的bash类似。
可以使用which命令查看其位置:
# which expect
/usr/bin/expect

2. set timeout 5 

设置超时时间5秒。"timeout -1" 为永不超时。

3. set passwd "iampasswd"
给变量passwd赋值,使用$passwd引用

4. spawn ssh root@$ipaddr 
spawn是进入expect环境后才可以执行的expect内部命令。
其主要功能是给ssh运行进程加个壳,用来传递交互指令。 

5. expect "password:" 
expect也是expect的一个内部命令。
其作用时判断上次输出结果是否包含字符串"password:",包含则立即返回,否则就等待超时后返回。 

6. send "$passwd\r" 
这里就是执行交互动作,与手工输入密码的动作等效。 
注意命令字符串的结尾要加上"\r"。

7. exp_continue的用法
可以继续执行下面的匹配。

8. expect eof
使用expect eof,登录后执行一段命令退出终端。执行完成后如果需要保持交互状态可使用interact 。

9. interact 
执行完成后保持交互状态,把控制权交给控制台,这个时候就可以手工操作了。
如果没有这一句登录完成后会退出。 

[例2-2] ssh登录主机,test2.exp内容如下(主机名和密码通过参数传给脚本,执行完成后留在远程终端)

#!/usr/bin/expect -f

set ipaddress [lindex $argv 0]
set passwd [lindex $argv 1]

set timeout 10

spawn ssh root@$ipaddress

expect {
"yes/no" { send "yes\r";exp_continue }
"password:" { send "$passwd\r" }
}

expect "*from*"
send "cd /tmp;touch b.txt\r"

interact

执行log如下,并且创建了文件b.txt

[root@xxx test]# ./test2.exp 192.168.22.22 iampasswd
spawn ssh [email protected]
[email protected]'s password:
Last login: Wed Mar  4 10:21:42 2020 from 192.168.11.11
cd /tmp;touch b.txt
[root@aaa22 ~]# cd /tmp;touch b.txt
[root@aaa22 tmp]#           => 停留在远程终端
[root@aaa22 tmp]#
[root@aaa22 tmp]# ls -l b.txt  => 检查是否生成文件b.txt
-rw-r--r-- 1 root root 0 Mar  4 17:25 b.txt
[root@aaa22 tmp]#

说明:

10.$argv 参数数组
expect脚本可以接受从bash传递过来的参数,可以使用[lindex $argv n]获得,n从0开始,分别表示第1个参数、第2个参数……

$argc 存储了参数个数,args被结构化成一个列表存在argv。$argv0 被初始化为脚本名字。
如果在第一行(#!那行)使用-d (debug参数),可以在运行的时候输出一些很有用的信息,例如

argv[0] = /usr/bin/expect argv[1] = -d argv[2] = ./test2.exp argv[3] = 192.168.22.22 argv[4] = iampasswd

[root@xxx test]# ./test2.exp 192.168.22.22 iampasswd
expect version 5.44.1.15
argv[0] = /usr/bin/expect  argv[1] = -d  argv[2] = ./test2.exp  argv[3] = 192.168.22.22  argv[4] = iampasswd
set argc 2
set argv0 "./test2.exp"
set argv " 192.168.22.22 iampasswd"
executing commands from command file ./test2.exp
……

$argc为命令行参数的个数,$argv0为脚本名字本身,$argv为命令行参数。
[lindex $argv 0] 或 [lrange $argv 0 0]表示第1个参数,[lrange $argv 0 4]为第一个到第五个参数。
注意:$argv不包含脚本名字本身。

 

[例3] sftp远程连接服务器取包

先看看手动执行命令的记录

[root@aaa ~]# sftp [email protected]
[email protected]'s password:
Connected to 192.168.11.11.
sftp> get haha.tar
Fetching /root/haha.tar to haha.tar
/root/SCA-NR-19.4.tar.gz            100%  47MB  25.6MB/s   00:02
sftp>
sftp> get abc.txt
File "/root/abc.txt" not found.
sftp>
sftp> exit
[root@aaa~]#

选定匹配的关键字,可以编辑如下脚本sftpfetchpkg.sh

#!/usr/bin/expect -f  
set user "root"
set ip "192.168.11.11"
set passwd "iampasswd" 
set filepath [lindex $argv 0 ]
set timeout 60  

spawn sftp $user@$ip   
expect {
"*assword:*"  {send "$passwd\r;exp_continue" }
"sftp>"  {send "get $filepath\r" }
}
expect "100%" {send "exit\r"}
expect eof

成功取包打屏如下,

[root@aaa test]# ./sftpfetchpkg.sh /root/haha.tar
spawn sftp [email protected]
Connecting to 192.168.11.11...
[email protected]'s password:
sftp> get /root/haha.tar
Fetching /root/haha.tar to haha.tar
sftp> [root@aaa test]#

要取的包不存在打屏如下,

[root@aaa test]# ./sftpfetchpkg.sh /root/wakaka.tar
spawn sftp [email protected]
Connecting to 192.168.11.11...
[email protected]'s password:
sftp> get /root/wakaka.tar
Couldn't stat remote file: No such file or directory
File "/root/wakaka.tar" not found.
sftp> [root@aaa test]#

扩展:python中使用expect -> Pexpect 模块使用说明 https://www.jianshu.com/p/cfd163200d12

参考文档:
expect用法  https://www.cnblogs.com/iloveyoucc/archive/2012/05/11/2496433.html
shell中expect介绍  https://www.cnblogs.com/yxh168/p/9028122.html
Shell脚本学习之expect命令  https://www.cnblogs.com/lixigang/articles/4849527.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章