subprocess参数使用shell=True没有继续运行是什么原因
Admin 2022-06-30 群英技术资讯 1002 次浏览
这篇文章给大家分享的是“subprocess参数使用shell=True没有继续运行是什么原因”,对大家学习和理解有一定的参考价值和帮助,有这方面学习需要的朋友,接下来就跟随小编一起学习一下吧。写的程序使用subprocess创建子进程运行其他程序,判断其他程序运行完后进行处理。
在subprocess使用了shell=True,判断用户程序退出的代码如下
while self.proc.poll() is None:
do_something
判断子进程是否运行结束,程序在子进程运行结束后,代码未向下继续运行,而是卡在了这个循环中。
百度后对shell参数的解释如下:
shell=True参数会让subprocess.Popen接受字符串类型的变量作为命令,并调用shell去执行这个字符串,当shell=False是,subprocess.Popen只接受数组变量作为命令,并将数组的第一个元素作为命令,剩下的全部作为该命令的参数。
通过查看服务器进程可以看到,仍然有进程存在,进程如下

为shell中运行的程序,由此可以得出,shell=true时,子进程在运行完后,shell并没有退出,而是卡在shell命令中,可由进程看到。

补充:Python踩坑之旅其一杀不死的Shell子进程
踩坑的程序是个常驻的Agent类管理进程, 包括但不限于如下类型的任务在执行:
a. 多线程的网络通信包处理
和控制Master节点交互
有固定Listen端口
b. 定期作业任务, 通过subprocess.Pipe执行shell命令
c. etc
发现坑的过程很有意思:
a.重启Agent发现Port被占用了
=> 立刻想到可能进程没被杀死, 是不是停止脚本出问题
=> 排除发现不是, Agent进程确实死亡了
=> 通过 netstat -tanop|grep port_number 发现端口确实有人占用
=> 调试环境, 直接杀掉占用进程了之, 错失首次发现问题的机会
b.问题在一段时间后重现, 重启后Port还是被占用
定位问题出现在一个叫做xxxxxx.sh的脚本, 该脚本占用了Agent使用的端口
=> 奇了怪了, 一个xxx.sh脚本使用这个奇葩Port干啥(大于60000的Port, 有兴趣的砖友可以想下为什么Agent默认使用6W+的端口)
=> review该脚本并没有进行端口监听的代码
一拍脑袋, c.进程共享了父进程资源了
=> 溯源该脚本,发现确实是Agent启动的任务中的脚本之一
=> 问题基本定位, 该脚本属于Agent调用的脚本
=> 该Agent继承了Agent原来的资源FD, 也就是这个port
=> 虽然该脚本由于超时被动触发了terminate机制, 但terminate并没有干掉这个子进程
=> 该脚本进程的父进程(ppid) 被重置为了1
d.问题****出在脚本进程超时kill逻辑
通过代码review, 找到shell具体执行的库代码如下:
self._subpro = subprocess.Popen(
cmd, shell=True, stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
preexec_fn=_signal_handle
)
# 重点是shell=True !
把上述代码改为:
self._subpro = subprocess.Popen(
cmd.split(), stdout=subprocess.PIPE,
stderr=subprocess.PIPE, preexec_fn=_signal_handle
)
# 重点是去掉了shell=True
Agent会在一个新创建的threading线程中执行这段代码, 如果线程执行时间超时(xx seconds), 会调用 self._subpro.terminate()终止该脚本.
表面正常:
启用新线程执行该脚本
如果出现问题,执行超时防止hang住其他任务执行调用terminate杀死进程
深层问题:
Python 2.7.x中subprocess.Pipe 如果shell=True, 会默认把相关的pid设置为shell(sh/bash/etc)本身(执行命令的shell父进程), 并非执行cmd任务的那个进程
子进程由于会复制父进程的opened FD表, 导致即使被杀死, 依然保留了拥有这个Listened Port FD
这样虽然杀死了shell进程(未必死亡, 可能进入defunct状态), 但实际的执行进程确活着. 于是1.1中的坑就被结实的踩上了.
本节扩展知识包括二个部分:
Linux系统中, 子进程一般会继承父进程的哪些信息
Agent这种常驻进程选择>60000端口的意义
扩展知识留到下篇末尾讲述, 感兴趣的可以自行搜索
Linux系统进程
Linux随机端口选择
程序多线程执行
Shell执行
1.子进程会继承父进程的资源信息
2.如果只kill某进程的父进程, 集成了父进程资源的子进程会继续占用父进程的资源不释放, 包括但不限于
listened port
opened fd
etc
3.Python Popen使用上, shell的bool状态决定了进程kill的逻辑, 需要根据场景选择使用方式
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:mmqy2019@163.com进行举报,并提供相关证据,查实之后,将立刻删除涉嫌侵权内容。
猜你喜欢
这篇文章主要介绍了Python和JS反爬之解决反爬参数 signKey,Python 反爬中有一大类,叫做字体反爬,核心的理论就是通过字体文件或者 CSS 偏移,接下来文章的详细介绍,需要的小伙伴可以参考一下
在大家的日常python程序的编写过程中,都会有自己解决某个问题的解决办法,或者是在程序的调试过程中,用来帮助调试的程序公式,本文总结了22个万用公式,感兴趣的可以了解一下
这篇文章主要介绍了Python实现文本文件拆分写入到多个文本文件的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
内容介绍一、序言二、配置环境二、鼠标控制1、获取鼠标位置函数以及测试源码2、控制鼠标左击/右击/双击函数以及测试源码3、控制鼠标移动/拖动4、控制鼠标滚轮滚动总结一、序言使用python控制按键无疑非
python中如何实现用return返回多个值?return语句可以返回多个值,以逗号分隔,实际返回的是一个tuple。
成为群英会员,开启智能安全云计算之旅
立即注册关注或联系群英网络
7x24小时售前:400-678-4567
7x24小时售后:0668-2555666
24小时QQ客服
群英微信公众号
CNNIC域名投诉举报处理平台
服务电话:010-58813000
服务邮箱:service@cnnic.cn
投诉与建议:0668-2555555
Copyright © QY Network Company Ltd. All Rights Reserved. 2003-2020 群英 版权所有
增值电信经营许可证 : B1.B2-20140078 粤ICP备09006778号 域名注册商资质 粤 D3.1-20240008