容易忽略的expect脚本问题,暗藏的僵尸进程,wait命令不要漏掉
问题描述
前几天有个小需求,用到expect脚本去循环的发送一些数据,主要问题代码如下:
#! /usr/bin/expect
while {true} {
set timeout 60
spawn telnet ip port
expect "]'.";
send "***********一些数据***********\r"
expect "*********一些回复************";
send "exit\r"
expect "Connection closeed by foreign host.";
expect eof
sleep 10
}
单单看到这段代码,并没有发现什么问题,但是运行几个小时之后,收到一个错误:
buffer overflow detected *** : /usr/bin/expect terminated
========Backtrace: ========
... ...
内存越界?开始排查原因,虽然走了一些弯路,不过终于还是找到了答案:
首先,我们查看该进程的pid,然后进一步通过pid去进程fd文件夹下看看
[root]# ps -ef|grep expect.sh
root 17761 30111 .....
[root]# cd /proc/17761/fd/
[root]# ls -a
...
可以看到该进程已经产生了非常多的子进程句柄,赶紧ps -ef|grep 17761看一下:
[root]# ps -ef|grep 17761
root 23424 17761 ... [telnet] <defunct>
root 23426 17761 ... [telnet] <defunct>
root 23431 17761 ... [telnet] <defunct>
root 23434 17761 ... [telnet] <defunct>
root 23438 17761 ... [telnet] <defunct>
root 23439 17761 ... [telnet] <defunct>
root 23455 17761 ... [telnet] <defunct>
...
原来这个脚本产生了大量的telnet僵尸进程,导致句柄都用完了,但看上面的脚本,每次telnet都退出了,也都expect eof结束了进程,怎么会变成僵尸进程呢?
原因分析
很多人expect脚本用的不多,基本都是参照网上的例子来完成自己的需求,然后网上的博客大多都是转载来转载去,这导致有些细节问题不常被提及。
首先spawn会开启一个子进程(spawn_id)去执行命令,expect eof用于等待进程结束,另外有一个close命令用于直接结束子进程(根据spawn_id来定位子进程)。问题在于eof 和 close都只是杀死子进程,但子进程变为僵尸进程依然存在进程列表中,僵尸进程会占用句柄,但是句柄是有限的,大量僵死进程的产生,导致整个脚本进程无法继续运行,报错退出。
网上的例子大多是流程式的脚本,不是本文这种循环运行的,所以等待eof后,主进程退出,将僵尸进程也回收了,因此不会有任何问题。
不退出主进程,还要及时回收僵尸子进程,很多语言都内置了相关的方法,expect脚本也不例外,wait就是负责给子进程收尸的。所以文章开头的脚本应该加上wait来及时回收telnet僵尸进程。
#! /usr/bin/expect
while {true} {
set timeout 60
spawn telnet ip port
expect "]'.";
send "***********一些数据***********\r"
expect "*********一些回复************";
send "exit\r"
expect "Connection closeed by foreign host.";
expect eof <---------此句可以换成 close,因为上面已经主动关闭了telnet
wait <----------------wait不可缺少
sleep 10
}
最后
代码不在乎简单复杂,很多东西虽然可以省略,但能做到步步为营也不失是一种优秀的品质。
容易忽略的expect脚本问题,暗藏的僵尸进程,wait命令不要漏掉的更多相关文章
- 分发系统介绍、expect脚本远程登录、expect脚本远程执行命令、expect脚本传递参数
7月19日任务 20.27 分发系统介绍20.28 expect脚本远程登录20.29 expect脚本远程执行命令20.30 expect脚本传递参数 20.27 分发系统介绍 公司业务逐渐扩大时, ...
- shell脚本嵌套expect脚本
#!/bin/sh echo "helo" password='xxxx' ###不能在下面的expect脚本段设置成 set password xxxx否则获取不到变量,单独的e ...
- 使用expect脚本语言写一键发布服务(代码发布、所有服务重启)
互联网服务有很多台服务,但是在上线的时候需要将这些服务版本都更新与个个都重启,下面的脚本语言,就是一键发布服务~ 1.在/home/weihu/deploy/ 目录下建下publish .publis ...
- Linux 下 expect 脚本语言中交互处理常用命令
Linux 下 expect 脚本语言中交互处理常用命令 1. #!/usr/bin/expect 告诉操作系统脚本里的代码使用那一个 shell 来执行.这里的 expect 其实和 Linux 下 ...
- Mac 让 iTerm2 记住用户名密码 expect 脚本
刚刚用iTerm2的时候,总是要一遍遍的敲用户名.密码. 我在想, 能不能像Windows的软件一样,可以直接让软件记住.然后只要点击一下,就直接ssh到远程服务器上面去了. 之后经过搜索,可以用ex ...
- expect脚本同步文件 expect脚本指定host和要同步的文件 构建文件分发系统 批量远程执行命令
自动同步文件 #!/usr/bin/expect set " spawn rsync -av root@.txt /tmp/ expect { "yes/no" { se ...
- 分发系统介绍 expect脚本远程登录 expect脚本远程执行命令 expect脚本传递参数
expect脚本远程登录 yum install -y expect yum install -y tcl tclx tcl-devel 自动远程登录 #! /usr/bin/expect set h ...
- 与服务器同步工程(expect脚本)
先看下我实际用的例子: #!/usr/bin/expect spawn rsync -vazu ssh-src/src wayne@192.168.5.2:~/projects/ expect &qu ...
- shell脚本通过expect脚本实现自动输入密码(使用expect)
背景:在远程文件下载时,需要输入对方的服务器密码,shell不支持交互输入内容,可以用下面两种方式实现 一.在shell脚本中嵌入expect来实现密码输入 expect是一个自动交互功能的工具. ...
随机推荐
- Dinic算法----最大流常用算法之一
——没有什么是一个BFS或一个DFS解决不了的:如果有,那就两个一起. 最大流的$EK$算法虽然简单,但时间复杂度是$O(nm^2)$,在竞赛中不太常用. 竞赛中常用的$Dinic$算法和$SAP$, ...
- RegExp对象的exec方法
RegExp对象的exec方法和String对象的match方法用法十分相似,分两篇博客讲讲其各自的用法和它们之间的异同. 下一篇讨论match方法的用法和两者的异同. 定义及语法 [定义] exec ...
- Bootstrap Modal多个弹出层顺序
Bootstrap Modal多个弹出层顺序与div的顺序关联.后来者居上:即div靠后的modal层弹出的时候会在上层. 比如上图所示,模态框2弹出的时候会在模态框1上面.
- 初级篇html。
什么是html? 超文本标记语言,标准通用标记语言下的一个应用. “超文本”就是指页面内可以包含图片.链接,甚至音乐.程序等非文字元素. 超文本标记语言的结构包括“头”部分(英语:Head).和“主 ...
- python单下划线、双下划线、头尾双下划线说明:
单下划线.双下划线.头尾双下划线说明: __foo__: 定义的是特殊方法,一般是系统定义名字 ,类似 __init__() 之类的. _foo: 以单下划线开头的表示的是 protected 类 ...
- eclipse调试 10个技巧
先提三点 不要使用System.out.println作为调试工具 启用所有组件的详细的日志记录级别 使用一个日志分析器来阅读日志 1.条件断点 想象一下我们平时如何添加断点,通常的做法是双击行号的左 ...
- xshell5 可用注册码
101210-450789-147200(可以激活Xshell5,而且可以升级) 亲测可用 只能用于xshell5
- 如何清除SQL 的登录名
复制路径 找到SqlStudio.bin 文件删除即可 SQL Server 2016 版本: C:\Users\%username%\AppData\Roaming\Microsoft\SQL Se ...
- oracle的乐观锁和悲观锁
一.问题引出 1. 假设当当网上用户下单买了本书,这时数据库中有条订单号为001的订单,其中有个status字段是’有效’,表示该订单是有效的: 2. 后台管理人员查询到这条001的订单,并且看到状态 ...
- 我的JS历史知识
话说在那long long ago的1995以前,绝大多数因特网用户都使用速度仅28.8kbit/s的猫(调制调解器)上网,人们注册成为某个网站的用户时,填写好资料,发送给服务器去验证,如果某一资料填 ...