文章目录

  • 一、前言
  • 二、最初的想法:直接获取脚本中的变量值
    • 1、获取运行中py脚本的变量值
    • 2、换一种方式
    • 3、为什么不能获取脚本中的变量
    • 4、下下策,使用使用python的gdb调试工具
  • 三、python脚本监听终止进程行为
    • 1、python的signal模块以及atexit模块
    • 2、使用os.kill()退出程序
    • 3、脚本监听中止信号代码实例
  • 四、python通过脚本名获取pid
    • 1、通过脚本名称获取pid
    • 2、脚本内获取pid
    • 3、单个脚本监听命令行kill行为

一、前言

需求是: 一个正在运行的脚本,当结束脚本的时候,需要获取里面的变量,如果变量值存在则执行插入数据操作。如果变量不存在则正常关闭脚本。

这个需求可以理解成是在要杀死脚本的时候,让脚本监听到这个终止事件,从而做一些事情,比如持久化数据之类的。在实现需求的时候碰到很多有意思的知识点,下面咱们就来讲一下这些知识点。

二、最初的想法:直接获取脚本中的变量值

刚开始是想着定义一个test()方法,当要结束a脚本的时候,先执行另一个b脚本,调用a脚本的test()方法获取变量,然后对比变量的值,符合条件就执行数据库操作等。

1、获取运行中py脚本的变量值

刚开始是想着获取脚本中的变量,例如变量名是test,通过类似于:

import a
print a.test

但是这种方式只能获取变量的初始值,比如在a脚本刚开始的时候,设置 test =1,后续代码中累加test的值,我们通过这种方式,获取的test的值一直都是1,并不能获取脚本中变量的实时值

2、换一种方式

参考:https://blog.csdn.net/shiyf/article/details/47093899

完全按照这个参考博客的代码,本地测试的结果还是一样的,并不能获取脚本中的变量。仔细想想也是,人家脚本运行的时候,肯定是在一套封闭的环境中运行,想从中拿到变量不太科学。虽然是这么想,但是并不知道其中的原理

3、为什么不能获取脚本中的变量

main.py 文件:

import otherisRunning = True
def shutdown():global isRunningisRunning = Falsedef main():while isRunning:# some logic hereother.check()if __name__ == '__main__':main()

other.py 文件:

import maindef check():someCondition = #some logic to check the conditionif someCondition:main.shutdown()

这个例子非常相似,这位朋友的main.py脚本是根据isRunning 变量一直循环运行的脚本。他想通过other脚本改变isRunning 的值,从而中止main.py脚本的运行,和咱们的需求很相似了,但是他也一直实现不了自己的需求,后来有大佬是这么解释的:

该问题与正在加载两次的main.py文件有关.当您将其作为脚本运行时,它首先作为__main__加载.它也被other.py导入为常规名称main。这两个副本彼此完全分开,并且具有单独的全局变量!当other.check调用main.shutdown来修改isRunning全局变量时,它只更改main.isRunning版本,而不是__main __.isRunning.主要功能是检查__main __.isRunning,它永远不会被改变。

这就能解释为什么上面咱们通过引入的方式,每次都只能获取变量的初始值,而不能获取运行中脚本的变量。那么是否真的毫无办法呢?

4、下下策,使用使用python的gdb调试工具

参考:https://blog.csdn.net/xuzhina/article/details/76733977

这块大家可以自己百度下,知识点还是挺多的,只是使用gdb调试工具,相当于要自己手动执行一些查询操作,而且过程比较复杂,并不建议使用这种方式。

三、python脚本监听终止进程行为

既然不能获取变量,那么能不能自己监听中止事件呢,当检测到脚本要停止的时候,从而执行一系列的操作。而且这种方式的话,相当于是在a.py脚本内完成的操作,那么直接使用脚本中的变量即可。

1、python的signal模块以及atexit模块

通过不断的百度,最终锁定了pythonsignal模块以及atexit模块。

signal模块:

通过模块的特定方法,可以监听到脚本终止事件,从而执行相关操作,主要的方法包括:

 signal.SIGHUP  # 连接挂断   (适用于nohub守护进程的关闭)signal.SIGILL  # 非法指令signal.SIGINT  # 连接中断   (ctrl + c 和 kill -2)signal.SIGKILL # 终止进程(此信号不能被捕获或忽略)signal.SIGQUIT # 终端退出signal.SIGTERM # 终止   (kill pid)signal.SIGALRM  # 超时警告signal.SIGCONT  # 继续执行暂停进程

atexit模块:

pythonatexit模块定义了一个register函数,用于在python解释器中注册一个退出函数,这个函数在解释器正常终止时自动执行,一般用来做一些资源清理的操作。

但是这个函数,如果脚本是非正常crash,或者通过os._exit()退出,都不会调用退出函数。而且kill -2ctrl +c这种退出也不能调用该函数,因此一般要与signal模块配合使用。

注意: 这两个模块都不能监听kill -9这种方式的终止脚本,因为执行kill -9之后,内核根本不听你多哔哔,直接就把进程强制删除了。

参考:
https://www.jianshu.com/p/2fef52b7a231
https://www.return520.com/posts/9865/

2、使用os.kill()退出程序

因为要模拟退出程序,首选是kill的方式退出程序,这里选择os.kill()的方式退出,该函数是模拟传统的UNIX函数发信号给进程,其中包含两个参数:

一个是进程名,即所要接收信号的进程;一个是所要进行的操作。
操作(第二个参数)的常用取值为:
SIGINT      终止进程     中断进程
SIGTERM   终止进程     软件终止信号
SIGKILL    终止进程      杀死进程
SIGALRM   闹钟信号

结合上面咱们对于signal模块的分析,选用signal.SIGTERM的方式是比较合适的,主要监听的是kill pid的方式。因此中止代码如下:

os.kill(PID, signal.SIGTERM)

3、脚本监听中止信号代码实例

a脚本:

import signal
import os
import time
def onsignal_term(a, b):print 'SIGTERM'
signal.signal(signal.SIGTERM, onsignal_term)
while 1:print 'id:', os.getpid()time.sleep(2)

b 脚本:

import getopt
import sys
PID = 1000
os.kill(PID, signal.SIGTERM)  # 注意此处的PID需要是int类型的
b脚本中的pid为a脚本的pid,先执行a脚本,然后执行b脚本,此时触发os.kill()函数,
a脚本中也会成功监听到signal.SIGTERM时间,从而执行onsignal_term()函数。

注意: onsignal_term()函数需要有两个参数,不过这两个参数咱们也用不着,写上就可以。

四、python通过脚本名获取pid

这一步更多的是完善上面的想法。通过pid杀死进程,a脚本成功监听终止事件。只是这个pid不能每次都手动查询把,这样太费劲了,那么能不能用过什么方式来获取到脚本的pid呢。

一种方案是通过传参的方式,把pid传进去,然后b脚本根据pid杀死进程;
一种方案是根据脚本名称获取pid,也是用传参的方式,传入脚本名称;

两种方案都是通过传参的方式,只是第一种方案的pid还需要手动查证或者脚本内打印pid,操作相对来说复杂点。第二种方案就简单多了,只要知道脚本名称即可,难点在于怎么通过脚本名称获取pid。这里选择第二种方案。

1、通过脚本名称获取pid

File = '脚本名称'
#直接写死文件名
PID = os.popen("ps -ef | grep  a.py" ).readlines()[0].split()[1]
#带上变量的文件名
PID = os.popen("ps -ef | grep  %s" % File).readlines()[0].split()[1]

这里采用脚本内调用linux命令行的方法来获取,通过os.popen()获取符合条件的进程,再调用read()或者readlines()等对shell的输出结果进行读取。

具体的可以参考:https://blog.51cto.com/2681882/2317053

2、脚本内获取pid

顺带记录一下吧,在脚本内获取脚本pid的方法:

os.getpid()

3、单个脚本监听命令行kill行为

以上都是双脚本的监听,那么a脚本自己是否可以监听命令行的操作呢,理论上肯定是可以的,那么咱们也来试试

脚本a.py 如上所示:

执行a.py如下:

ljf@ljf:/var/www/python/Python2$ python2 a.py
id: 6340
id: 6340

按照脚本内容,会一直打印pid,直到捕获到kill命令。

执行kill 6340,则脚本停止并打印SIGALRM:

id: 6340
id: 6340
SIGALRM

其实单脚本和多脚本本质上是差不多的,我们在做多脚本的时候,顺带就也把单脚本的给做了,主要是看各自的业务吧。我这边为了给DBA方便,还是选择多脚本,毕竟项目也多,直接输入脚本名辨识度会高一些,而且也会更加安全。

如果要监听ctrl+c或者kill -2 pid这种模式的中断进程,那么可以选用:signal.signal(signal.SIGINT, onsignal_term) 经过测试,这种方式也完全没问题。当然,也可以选择两种方式都给写上,这样就能监听:kill pid ,ctrl + c , kill -2 pid ,建议是能同时监听多种情况,更方便一些。

身为一个python小白,以上很多知识点都是值得好好总结的,奈何技术有限,希望以后有机会讲一讲“why”,而不是单纯的“how”。

end

python脚本如何监听终止进程行为,如何通过脚本名获取pid相关推荐

  1. python全局键盘监听(pynput快捷键);利用pywin32快速截屏并生成视频

    python全局键盘监听(pynput快捷键):利用pywin32快速截屏并生成视频 第一次在CSDN写博客,有点小紧张(/ω\) 以下内容完全个人理解,有错误请指出~ 最近在用python做一个小工 ...

  2. python应用系列教程——python使用scapy监听网络数据包、按TCP/IP协议进行解析

    分享一个朋友的人工智能教程.零基础!通俗易懂!风趣幽默!还带黄段子!大家可以看看是否对自己有帮助:点击打开 docker/kubernetes入门视频教程 全栈工程师开发手册 (作者:栾鹏) pyth ...

  3. android监听程序被杀死,Android 监听主进程被杀

    当按多任务键时,然后清除所有程序或者杀死单个程序时,如果要监听这个动作的话,可以在一个service里监听. 效果如下: 可以看到,在多任务窗口中,左滑结束进程和清除所有进程后,都会自己再打开应用,代 ...

  4. linux netstat Netstat是在内核中访问网络连接状态及其相关信息的程序,它能提供TCP连接,TCP和UDP监听,进程内存管理的相关报告。

    在Internet RFC标准中,Netstat的定义是: Netstat是在内核中访问网络连接状态及其相关信息的程序,它能提供TCP连接,TCP和UDP监听,进程内存管理的相关报告. Netstat ...

  5. Python 键盘鼠标监听

    异想天开的想记录一下自己每天的键盘键位走向,于是就在网上搜索了一下相关的实现,然后就发现了一个第三方的库pyHook.封装的很好,我们只需要傻瓜式的调用里面的API就可以了. 下面是我在使用pyHoo ...

  6. 监听服务端口及邮件报警脚本

    监听端口脚本 vim /root/dkjc.sh#!/bin/bash #name:王康Dk="8000 8080 3306" while : dofor i in $Dkdone ...

  7. 查看 linux 硬件信息:内存、分区、系统、环境变量、防火墙、路由、端口监听、进程、CPU...

    前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家.点击跳转到教程. 一.linux CPU大小: 其实应该通过Physical Processor ID来区分单核和双核 ...

  8. 监听springboot进程,如果关闭就重启

    参考文章 https://blog.csdn.net/u014672513/article/details/116760083 @echo off set AppName=jar包名称 set App ...

  9. python实现键盘监听

    这里来展示一个比较有意思的python功能模块:pynput,这个模块里面有关于鼠标和键盘的一些操作,这里给大家分享的是监听键盘操作. 安装 pip install pynput # conda or ...

最新文章

  1. 对MIME格式的邮件文件进行解码获取其可读内容和附件等
  2. HDU 1693(状态压缩 插头DP)
  3. vs2017 不能加载.vdproj
  4. 2020-07-14 CVPR2020 i3DV论文讨论(4) 笔记
  5. 我觉得要技术者上升到整体去考虑会好点
  6. android system window,Android之属性fitsSystemWindows
  7. onlinezakladki 右键菜单还原
  8. 【Leetcode】Python实现字符串转整数 (atoi) - 详细备注,保证小白看懂
  9. [删括号][判断可行性的dp]
  10. 【转载】CMMI与敏捷开发模式比较
  11. origin8.0快速实现多X,Y绘制
  12. 第18章 基于物理的渲染
  13. 【HAVENT原创】Spring Boot 跨命名空间调用外部依赖包
  14. vnc远程软件,盘点六款你值得拥有的vnc远程软件
  15. 惊蛰时节,最好看的微信公众号图文排版,全在这里了
  16. 目前住院病人主要由护士护理,这样做不仅需要大量护士,而且由于不能随时观察危重病人的病情变化,还可能会延误抢救时机。某医院打算开发一个以计算机为中心的监护系统,试写出问题定义并且分析开发这个系统的可行性
  17. NOJ1635看望朋友
  18. mysql数据库管理-2019整理
  19. 为什么重大疾病保险最好要选择保障终身?
  20. access创建窗体特别慢_Access 2016 创建窗体

热门文章

  1. 115网盘如何打开php文件格式,115网盘下载:因纽特语教材(初级+高级+音频)
  2. android adb恢复出厂设置,android开发分享擦除数据/通过ADB恢复出厂设置
  3. gateway 内存溢出问题_带你学习jvm java虚拟机 arthas/性能调优/故障排除/gc回收/内存溢出等...
  4. tenserflow.js 环境搭建
  5. win 安装Polygon
  6. dbface backbone
  7. 在windows10上搭建caffe
  8. 可自动关闭的alert方法
  9. pytorch mseloss bceloss 对比
  10. opengl嵌入pyqt5编译的分割窗口中