shell-expect使用笔记

     需要ssh上多台主机进行相同操作,重复劳作是枯燥的,所以写个shell脚本实现。用到了expect。

     网上有不少expect的教程,都大同小异,没有说得很详细的。求人不如求己,man expect瞅了瞅,再看看tcl语法,就差不多了。expect用的是tcl语法,所以要用expect实现一些功能,需要学一些tcl的知识。这里有个不错的网站学习tclhttp://www.yiibai.com/tcl/

     先贴一个expect实现scp传输的实例:

#!/usr/local/bin/expect  
set timeout 10  
set host [lindex $argv 0]  
set username [lindex $argv 1]  
set password [lindex $argv 2]  
set src_file [lindex $argv 3]  
set dest_file [lindex $argv 4]  
spawn scp $src_file $username@$host:$dest_file
expect {
"(yes/no)?"
   {
    send "yes\n"
    expect "*assword:" { send "$password\n"}
   }
"*assword:"
   {
    send "$password\n"
   }
}  
expect "100%"  
expect eof  

     可以简单地说,expect是一个阻塞的switch,sp awn执行一个命令后,expect会匹配返回值,并执行相应的操作。


1.expect格式

	expect {
		"string"  #-re可以正则匹配字符串
			{
				command
			}
		status
			{
				command
			}
	}
或者

expect "string" {command}
(注意,expect右边必须有值,把括号写在下一行会报错!)

   其中command可以是tcl语法命令,如puts,也可以是expect命令,如send,exp_continue,exit等等;而status是指expect的状态信息,如timeout,connected。


2.tcl语法

    tcl是一种简单的脚本语言,这里简单介绍一些需要用到的语法。

    puts   打印变量或字符串,调试必备

    set  赋值,sethost [lindex $argv0就是将参数0赋值给变量host,其中,[] 括起命令,执行括号内命令后返回结果,lindex是取列表中的某个参数,$argv则是参数列表。

    while { } {command} while循环,和bash类似,while后面要留一个空格,右括号后面再留一个空格,我就是在这里遇到了莫名的报错。。


3.timeout&exp_continue

    set timeout 10是设置超时时间。如果过了超时时间控制台仍旧没有返回,或者返回的都不符合期待的字符串,就会超时,如果设置了timeout的动作,就会执行该动作,否则程序继续向下执行。

    写了一个简单的timeout如下

set timeout 1
spawn ssh ***
expect{
 timeout {exp_continue;puts timeout\n}
}
    设置超时时间为1秒,ssh一般来说1秒钟还没有返回,所以会触发timeout状态。然而这段代码并没有打印出timeout,原因是exp_continue,它会重置定时器,继续等待一个超时时间,类似于while循环中的continue会跳过其后的代码开始下一次循环,exp_continue也会跳过其后的代码开始下一次等待。


4.附源码

#!/usr/local/bin/expect  
set timeout 10 
set host [lindex $argv 0]  
set username [lindex $argv 1]  
set password [lindex $argv 2]  
set filename [lindex $argv 3]
set file_data [open "./$filename" r]
spawn ssh $username@$host
expect {
"(yes/no)?"
   {
    send "yes\n"
    expect "*assword:"  {
                send "$password\n"
                expect "try again"      {send_user "password is wrong\n";exit}
        }

   }
"*assword:"
   {
                send "$password\n"
                expect  {
                        "try again"     {send_user "password is wrong\n";exit}
                        #connected send_user "connected"
                        }

   }

}
while {[gets $file_data command]>=0} {
        send "$command \n"      
        expect "*#"
}
send "exit\n"
close $file_data

    将所要进行的命令逐行写在一个文本文件中,与脚本放在同级目录下,即可实现一步操作。



你可能感兴趣的:(shell-expect使用笔记)