最近使用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的处理逻辑为可能的输出设定处理逻辑。
转载请注明转自高孝鑫的博客
expect的工作原理:
简单来说就是,你执行一个行为,然后你预期会有哪些结果,并为每种结果设定处理逻辑。
以远程ssh登录为例,
你执行 “ssh host@ip ” 过程中,预期会有3种输出
1. 询问密码
2. 问你是否确定要建立ssh连接
3. 密码错误
对于的示例代码为:
#!/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
eof {exit 1} #这个不能少
}
sleep 1
}
send
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()
{
end:
}
需要注意的是:
1. expect内部使用时钟信号,如果调用程序也使用了时钟信号的话可能会有问题,如ACE。
2. expect 使用了全局变量,所以是线程不安全的。。。。
折中的办法就是使用 popen调用expect脚本,然后用类似expect的处理逻辑为可能的输出设定处理逻辑。
转载请注明转自高孝鑫的博客