天天看点

SHELL脚本之另一种脚本EXPECT

“shell是世界上最好的脚本语言!”🌚🌚🌚

shell脚本虽然可以很方便的帮我处理一些琐碎的问题,但同时也有它的缺点:shell脚本是一种无交互式的脚本

什么叫无交互式呢,比如说删除这个命令

[[email protected] ~]# rm test
rm:是否删除普通文件 "test"?
           

在删除一个文件时,系统会给一条交互信息询问是否要删除文件,所以删除一个文件需要有两个操作:删除->确认删除(当然你也可以加-f来强制删除就不会有这个交互过程了,这里只是举一个例子),而shell执行命令时实际上只能一条一条的执行,并不能处理这些交互过程

所以这就引出了本文的主角:expect,一种交互式的脚本工具

其他我就不多说了,直接来将expect怎么使用吧

  • 安装:

    yum install expect

  • 编写expect脚本:
    • 脚本名一般以

      .exp

      结尾
    • 第一行为

      #!/usr/bin/expect

  • 定义变量:
    • set 变量名 值

    • set 变量名 [lindex $argv 0]

      :从命令参数数组中取值
    • 特殊变量:
      • $argc

        :参数个数,相当于shell中的

        $#

      • $argv

        :所有参数的数组,索引从0开始
  • 语句:
    • set 定义变量

      • set timeout 300

        :将超时时间设置成300(秒)
    • spawn COMMAND

      :监控命令的输出
    • expect “STRING” { send “STRING” }

      :捕获输出,并执行相应命令
    • send “STRING\r”

      :发送“STRING”,比如删除文件时需要回复yes表示确认删除,就可以写

      send “yes\r”

      ,注意最后需要换行,不然输出结果看起来会比较乱
    • send_user “STRING”

      :执行expect时前台会被占用,这里相当于在执行完脚本中的某一个任务时发给终端的一条提示,相当于shell中的

      echo

    • exp_continue

      :继续捕获输出,expect用{}框起来的块中可以实现类似case的判断效果,这里的exp_continue就相当于case语句中每一判断条件的break
    • interact

      :暂停脚本的执行,将控制权交还给用户,直到用户
    • exit

      :退出脚本
    • expect eof

      :捕获退出信号,若捕获不到则会阻塞等待,超时自动退出

下面是一些相关例子:

模拟ftp登录并下载文件

  • 工作准备:
    • 关闭防火墙:

      iptable -F

    • yum install vsftpd

    • systemctl restart vsftpd

    • cp /etc/fstab /var/ftp

    • yum install ftp

#!/usr/bin/expect

set ip [lindex $argv 0]
set name "ftp"
set pass ""
set file "fstab"

spawn ftp $ip
expect "Name"
	send "$name\r"
expect "Password"
	send "$pass\r"
expect ">" {
	send "get $file ftp_$file\r"
	send "exit\r"
}
expect eof
send_user "ALL COMMAND FINISHDED\n"
           

测试用例:

[[email protected] ~]# ./ftp.exp 127.0.0.1
spawn ftp 127.0.0.1
Connected to 127.0.0.1 (127.0.0.1).
220 (vsFTPd 3.0.2)
Name (127.0.0.1:root): ftp
331 Please specify the password.
Password:
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> get fstab ftp_fstab
local: ftp_fstab remote: fstab
227 Entering Passive Mode (127,0,0,1,246,62).
150 Opening BINARY mode data connection for fstab (501 bytes).
226 Transfer complete.
501 bytes received in 0.000192 secs (2609.38 Kbytes/sec)
ftp> exit
221 Goodbye.
ALL COMMAND FINISHDED
[[email protected] ~]# 
[[email protected] ~]# ll | grep 'ftp_'
-rw-r--r--. 1 root root      501 3月   5 22:28 ftp_fstab
           

用shell脚本批量分发公钥(将所有)

  1. 创建密钥分发expect脚本

    key.exp

#!/usr/bin/expect 
set timeout 300
set password "redhat"
set ip [lindex $argv 0]
spawn ssh-copy-id [email protected]$ip
expect {
	"yes/no"  {
		send "yes\r"
		exp_continue
	}
	"password: " {
		send "$password\r"
		exp_continue
	}		
	"No route to host" {
		exit 1
	}		
	eof
}
           
  1. 创建shell脚本,调用expect
#!/bin/bash

. /etc/init.d/functions


for i in `cat /root/ip.txt`; do
	expect /root/key.exp $i > /dev/null 2>&1
 	if [ $? -eq 0 ]; then
        	action "$i" /bin/true
	else
        	action "$i" /bin/false
	fi
done
           

继续阅读