转expect 文一篇。

用expect实现通过scp自动上传文件的脚本

  最近在公司写了一个scp自动向远程主机传文件的脚本。由于scp使用交互式的方式获取密码,因此要实现脚本的自动登陆有两种方法,一种是配置信任,但是貌似,就目前我所了解到的,配置信任无法限制权限问题,一旦配置了ssh的信任,则对方可以通过ssh、sftp等各种方式登陆主机。。。。
    所以使用第二种方法,expect。
    expect是基于tcl的一种脚本语言,它主要是为了实现交互式的脚本(貌似perl也可以做到,但是我不会-_-)。
    expect并不在linux的默认安装包里,因此需要独自安装。源码很好找。另外,expect的安装需要tcl的源码。。

Tcl安装方法:下载tcl包。(建议8.4.13,因脚本己在8.4.13下测试通过。下同),解压后进入源码根文件夹,执行以下命令

         Cd unix

         ./configure --prefix=/usr/tcl

         Make

         Make install

         Cd ..

         cp ./unix/tclUnixPort.h ./generic/

         

    不要删除源码。安装expect需要用到

 

然后解压expect包,(建议5.43.0)进入expect源码根文件夹

./configure -prefix=/usr/expect -with-tcl=/usr/tcl/lib -with-x=no -with-tclinclude=/root/tcl8.4.13/generic

加粗斜体部分为你的tcl源码包的文件夹

然后

         Make

         Make install


 

    这样expect就安装好了,自动传文件的脚本在最后(-_-刚刚用cublog,不知道怎么在代码后面写正文,所以直接把代码放最后了)

   

   set remotedir [lindex $argv 0]

   这是expect声明变量的方法,中括号内表示的是输入的第一个参数,expect与其它脚本稍有不同,它的第一个参数是argv0,而其他脚本一般为argv1


 

    set timeout 10000000000

   这句是设置超时时间。应该是秒,但是好像不大准确的样子。默认的timeout是10,我设成这么大是因为传送的文件比较多,估计10秒内传不完


 

   if {$file == 0} { if {$load == 0} {spawn scp $mydir $remotedir} else {spawn scp $remotedir $mydir } }

   这就是expect中恶心的if-else语句了。。。这个东西写了我很久,它的条件判断需要放在大括号内,大括号不能独成一行(可以理解,没有";"嘛),另外,else貌似也不能独成一行,必须接到前一个if的后面。而且与大括号之间要有间隔-_-。。具体没搞懂,不过直接写在一行内肯定不会错。


 

   expect "Are you sure you want to continue connecting (yes/no)?" { send "yes\r" } "Password:" { send "$password\r" }"Permission denied*" { break } "*No route to host" { break } "*No such file or directory" { break } timeout { break } eof {break }

   这句就是整个脚本最关键的了。expect后面跟了很多字符串,如果得到了与某个字符串相匹配的串,那么执行该字符串后面的语句。比如得到了"Password:",那就执行send "$password\r"。这里也不能分行写。我从网上找的教程有一个分行写。。害死我了

   另外,求高人指点如果用expect spawn一个没有输出的程序?比如

     ls -l > log.txt

#!/usr/expect/bin/expect -f

#usage: scp.exp remotedir mydir password load file
#argument: load , 0 for upload, 1 for download
#     file , 0 for single file , 1 for directory

set remotedir [lindex $argv 0]
set mydir [lindex $argv 1]
set password [lindex $argv 2]
set load [lindex $argv 3]
set file [lindex $argv 4]
set timeout 10000000000
if {$file == 0} { if {$load == 0} {spawn scp $mydir $remotedir} else{spawn scp $remotedir $mydir } }
if {$file == 1} { if {$load ==0 } {spawn scp -r $mydir $remotedir } else{spawn scp -r $remotedir $mydir } }
for {} {1} {} { expect "Are you sure you want to continue connecting (yes/no)?" { send "yes\r" } "Password:" { send "$password\r" }"Permission denied*" { break } "*No route to host" { break } "*No such file or directory" { break } timeout { break } eof { break } }
expect eof


    PS:有一个问题需要注意一下,如果在expect中
      spawn ls /*
    会出错,提示找不到/*这个文件,看起来expect是把*解释成了普通字符而非正则表达式。
原文地址:https://www.cnblogs.com/dracula/p/1913797.html