报警器参考:人体静电释放报警器
一、返回值校验
返回值校验始终是一个安全可靠软件或者说软件或者说作业的基本流程,无论执行什么工作,都应该告诉使用者这个子进程执行的结果如何,就是通常所说的,你倒是吱一声? 6杂趀xpect来说,它的情况是比较特殊的,它执行ssh执行远程进程的时候,我们在expect中读取的只能是ssh的返回值,而不是通过ssh执行的命令的返回值。
如果要获得ssh执行的远端进程的返回值,这个是用通用的方法就可以了。例如我们执行了一个scp命令,执行之后可以在命令提示符的正则表达式中做特殊处理,方法就是添加一些变量表示是第几次出现命令提示符命令,之后更具次数来执行shell的内置变量 $? 获得刚刚执行的子进程的返回值,再通过senduser或者其它的脚本变量将这个返回值保存起来,在进程退出的时候将这个值返回给执行者。
现在考虑一下对于一个本地进程的返回值如何获得。执行本地命令并不是一个稀缺的现象,例如我们在本地执行ync命令,此时我们希望得到的其实就是这个ync的返回值。
二、网络上的解决方法
网络上常见的说法就是通过
catch wait result
这里的catch并不是expect的命令,而是expect的基础上建立的tcl库中的一个函数,所以在expect的代码中找不到该命令的实现。说到这里,我们可以看到tcl的设计思想对于命令的影响。通常的脚本例如bash,设置一个变量是通过 var=val的方式来定义一个变量的值,而tcl中则是通过 set var val来实现,这和tcl中提出的所有内容都是命令一致的。bash中对于变量赋值的语法其实是通过专门的解析方法来实现的,它会在每个命令中搜索是否存在有等号的存在。假设如果是通过set,这就是一个普通的命令,它有两个参数,这样词法分析也简单一些。简单的原因不是在于不能实现复杂的功能,而是因为简单的东西具有更强的扩展性和更好的可维护性,这些对于软件的维护来说都是非常有价值的属性。
wait是expect的内置命令,所以可以看一下这个命令对应的函数实现:
argv++;
argc--;
for (;argc>0;argc--,argv++) {
if (streq(*argv,"-i")) {通过-i可以指定等待那个子进程的返回,因为expect同样是可以同时spawn多个子进程的,所以这个-i是有意义的。
argc--; argv++;
if (argc==0) {
exp_error(interp,"usage: -i spawn_id");
return(TCL_ERROR);
}
chanName = *argv;
} else if (streq(*argv,"-nowait")) {
nowait = TRUE;
}
}
if (!chanName) {
if (!(esPtr = expStateCurrent(interp,0,0,1))) return TCL_ERROR;
} else {
if (!(esPtr = expStateFromChannelName(interp,chanName,0,0,1,"wait")))
return TCL_ERROR;
}
……
if (result == -1) {
sprintf(interp->result,"%d %s -1 %d POSIX %s %s",
esPtr->pid,spawn_id,errno,Tcl_ErrnoId(),Tcl_ErrnoMsg(errno));
result = TCL_OK;
} else if (result == NO_CHILD) {
exp_error(interp,"no children");
return TCL_ERROR;
} else {
sprintf(interp->result,"%d %s 0 %d",
esPtr->pid,spawn_id,WEXITSTATUS(esPtr->wait));
也就是说,wait命令的返回值是一个"%d %s 0 %d"格式的字符串,所以我们可以通过
set result wait
来说的子进程的返回值,如果通过wait没有指定等待的接口,默认是当前spawn的进程编号。而结果的第四个字段就是通过waitpid获得子进程的返回值。
三、如果没有执行wait
这里可以看到,如果没有执行wait,expect是始终不会执行waitpid,这样多次执行spawn之后派生的所有子进程在expect退出之前都是处于Zombie状态。
四、一个例子
spawn echo we have echoed
expect eof
spawn echo we echoed again
set result [ wait result]
puts $result
sleep 12345
输出
spawn echo we have echoed
we have echoed
spawn echo we echoed again
2907 exp5 0 0
此时有兴趣的同学可以通过 ps aux | grep echo
看一下,系统中会有一个Zombie状态的进程,如果去掉之前的wait作,系统中会有两个Zombie的echo进程。