expect 使用笔记

最近使用expect 进行远程命令调用,摸索过程中有所收获,记录之。

expect的工作原理:

简单来说就是,你执行一个行为,然后你预期会有哪些结果,并为每种结果设定处理逻辑。
以远程ssh登录为例,
你执行 “ssh host@ip ” 过程中,预期会有3种输出
1. 询问密码
      对应的处理逻辑为输入密码
2. 问你是否确定要建立ssh连接
      对应的处理逻辑为输入 ‘yes’
3. 密码错误
      对于的处理逻辑为 退出exit

对于的示例代码为:

#!/usr/bin/expect -f 
set ip 192.168.122.110
set password 111111
set timeout 10 
spawn ssh root@$ip 
expect {   
"*yes/no" { send "yes\r"; exp_continue} 
"*password:" { send "$password\r" }   

expect {
"*Permission denied*" {exit 2}
"#*" {}
}
 

等待命令执行结束:

expect以获取待命令行输出就会返回,但那时候程序可能并没有执行完,因为有的程序在执行过程中会有输出。
解决办法是循环等待直到获取到程序执行结束对于的输出,下面是一个示例:


#!/usr/bin/expect -f 
set ip 192.168.122.110
set password 111111
set timeout 10 
spawn ssh root@$ip 
expect {   
"*yes/no" { send "yes\r"; exp_continue} 
"*password:" { send "$password\r" }   

expect {
"*Permission denied*" {exit 2}
"#*" {}
}
# 下面是要执行的命令
send "/usr/local/Calpont/bin/cpimport -m2 test infi -l /root/gen.dat\r"

while 1 {
expect {
"*not exist*" {break}
"*Cpimport Failure*" {break}
"rows processed and" {break}
"*ERR  :*" {break}
eof {exit 1} #这个不能少
}
sleep 1
}
send  "exit\r" 
expect eof


c/c++中使用expect

c和c++中也可以使用expect,需要安装相应的dev库,ubuntu下执行如下命令进行安装:
apt-get install tcl-dev
apt-get install expect-dev

注:如果执行安装expect-dev会自动安装tcl8.5-dev,导致的结果就是你需要自己手动在 /usr/include下创建一个tcl的软连接到 /usr/include/tcl8.5。

下面是示例代码:

#include
#include
#include
#include
#include
#include
#include

using namespace std;

int main()
{
      extern int exp_timeout;
      exp_timeout = 100;
      Tcl_Interp *tcl;
      tcl = Tcl_CreateInterp();
      if (Expect_Init(tcl) != TCL_OK)
      {
              puts("failure");
              return 1;
      }
      int fd = exp_spawnl("ssh", "ssh", "-p 22", "root@192.168.122.110",
                                              "echo 'abbbb\r\nddd 5 rows processed and 5 rows inserted\r\nkkkkk';", (char *)0);
      if(fd < 0)
      {
              cout<<"Fail to ssh"<<endl;
              return -1;
      }
      int result;
      char *p = NULL;
      char *p_end = NULL;
      string match_rows;
      //predefine some expected responses
      string ask_passw("*assword: ");
      string wrong_passw("*Permission denied, please try again.");
      string ask_continue("(The authenticity of host)(.)*(Are you sure you want to continue connecting (yes/no)?)");

      result = exp_expectl(fd, exp_glob, ask_passw.c_str(), 0, exp_glob, wrong_passw.c_str(), 1, exp_glob, ask_continue.c_str(), 2, exp_end);

      string passw("111111\r");
      switch (result)
      {
      case 0:
          write(fd, passw.c_str(), passw.length());
          break;
      default:
          cout<<"wrong connect"<<endl;
          goto end;
      }
      result = exp_expectl(fd, exp_glob, ".*", 0, exp_end);

      cout<<"tmp is "<<exp_match<<endl;
      p = strstr(exp_match, "rows processed and ");
      p += 19;
      p_end = strchr(p, ' ');
      match_rows.append(p, p_end - p);
      cout<<"rows is "<< match_rows.c_str() << endl;
end:
      Tcl_DeleteInterp(tcl);
}

需要注意的是:
1. expect内部使用时钟信号,如果调用程序也使用了时钟信号的话可能会有问题,如ACE。
2. expect 使用了全局变量,所以是线程不安全的。。。。

折中的办法就是使用 popen调用expect脚本,然后用类似expect的处理逻辑为可能的输出设定处理逻辑。

转载请注明转自高孝鑫的博客
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值