shell-expect使用笔记

    xiaoxiao2021-03-25  80

         需要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     将所要进行的命令逐行写在一个文本文件中,与脚本放在同级目录下,即可实现一步操作。

    转载请注明原文地址: https://ju.6miu.com/read-14071.html

    最新回复(0)