长亭百川云 - 文章详情

Python 技巧 | 程序内开命令行子进程

未闻Code

45

2024-07-13

本文旨在解决 Python 程序内命令行子进程的问题。

首先需要总结一下 windows 和 linux 分别的 shell 命令,包括端口,进程,PID 等。

最后比较内置库 subprocessing 和第三方库 psutil,然后分别实现 Python 控制子进程的 demo。

查看端口占用情况

netstat 是通用命令,但是参数不同

windows 使用 -ano 参数,代表 all & numerical & owning pid ,这里的 -n 指用的是纯数字地址,不用电脑的名字去替换 0.0.0.0 这种特殊地址

Linux 使用 -tunlp 参数,代表 tcp udp numerical listen PID/Program,这里的 -n 和 Windows 一样

如果要找到特定的端口,Windows 使用 findstr 命令

`netstat -ano | findstr "8000"   `

Linux 使用 grep 即可

通过进程名查看 pid

Linux 使用 ps -aux 命令,第二列就是 PID

Windows 使用 tasklist 命令,第二列就是 PID

通过命令名查看 PID

这里不讲 Linux —— Linux 在 Python 中可以直接抓住 PID,Windows 抓不住才要说

首先我们用 python.exe 运行 .py 文件,.py 文件内容如下,是个不断输出 yes 的程序

使用 wmic 命令如下,可以找到相关 CommandlinePID

wmic process where "name='python.exe'" get processid,commandline  

反过来也可以通过 PID 查询进程相关信息

wmic process where "ProcessId='6752'" get processid,commandline  

根据 PID 杀死进程

Linux 使用 kill <pid> 命令瞄准 PID 杀死进程,强制杀死使用 kill -9 <pid>,这里涉及到 linux signals,明天专门写一篇 linux signals 来阐述其中原理

Windows 使用 taskkill /T /F /PID <pid> 来瞄准 PID 杀死进程,使用 taskkill /? 可以查看命令的相关内容,其中这三个参数的意思如下

`/T Terminates the specified process and any child processes which were started by it.   /F Specifies to forcefully terminate the process(es).   /PID  Specifies the PID of the process to be terminated.   `

terminate force pid,就是强制终止该 PID 对应的进程以及所有子进程

Python 和 shell 交互

第一种方案是内置库 subprocess,第二种方案是第三方库 psutil

第三方库无疑是建立在内置库的基础上做了一些封装的,在没有一些非常定制化的需求时,可以完全胜任我们的任务。但是我倾向于搞懂底层原理,为了防止以后有更牛逼的第三方库出现时我不知所云。

我们现在来执行一个 .py 文件以子进程的方式执行另一个 .py 文件

`"""   Use subprocess.Popen and psutil.Popen to start subprocess   """      import re   import time   from typing import Optional   import subprocess   import psutil      class SayYesController:          def __init__(self) -> None:           self.file = "say_yes.py"           self.pid : Optional[str] = None              def open_sub_by_subprocess(self):           command = f"python {self.file}"           subprocess.Popen(command,shell=True)              def get_pid_by_subprocess(self):           command = """wmic process where "name='python.exe'" get processid,commandline"""           subprocess_info_block = subprocess.check_output(command,shell=True)           print(subprocess_info_block)           for info in str(subprocess_info_block).split(r'\n'):               if "say_yes.py" in info:                   self.pid = re.findall('(\d+)',info)[0]                   print("Parsed PID is",self.pid)                   break          def kill_pid_by_subprocess(self):           if self.pid is None:               return           subprocess.call(f'taskkill /T /F /PID {self.pid}',shell=True)          def test_subprocess(self):           self.open_sub_by_subprocess()           time.sleep(10)           self.get_pid_by_subprocess()           self.kill_pid_by_subprocess()          def test_psutil(self):           process = psutil.Popen(f"python {self.file}")           time.sleep(10)           process.terminate()          def run(self):           print("===== test subprocessing =====")           self.test_subprocess()           print("===== test psutil =====")           self.test_psutil()         if __name__ == "__main__":       bot = SayYesController()       bot.run()   `

运行的结果是都成功了,但是前一种方法是真的很费时费力,后面只要一个 .terminate() 就自动帮你找到进程然后杀死了

总结

今天总结了 Windows 和 Linux 的端口,进程,PID 的命令,然后使用 Python 交互了一下命令行,发现就找到 PID 然后杀死对应进程这一件事来说,psutil 确实是大大减少了我们的时间花费

对了,最后的最后我们看一下 Mac 和 Linux 是怎么搞出进程号的

`p = subprocess.Popen('python test.py', shell=True)   p = p.pid   `

哈哈是可以直接搞到 PID 的。又是对 Windows 无奈的一天,不过现在有 psutils 库,这也不是事儿啦!

更多每日开发小技巧

尽在****未闻 Code Telegram Channel !

END

未闻 Code·知识星球开放啦!

一对一答疑爬虫相关问题

职业生涯咨询

面试经验分享

每周直播分享

......

未闻 Code·知识星球期待与你相见~

一二线大厂在职员工

十多年码龄的编程老鸟

国内外高校在读学生

中小学刚刚入门的新人

在“未闻 Code技术交流群”等你来!

入群方式:添加微信“mekingname”,备注“粉丝群”(谢绝广告党,非诚勿扰!)

相关推荐
关注或联系我们
添加百川云公众号,移动管理云安全产品
咨询热线:
4000-327-707
百川公众号
百川公众号
百川云客服
百川云客服

Copyright ©2024 北京长亭科技有限公司
icon
京ICP备 2024055124号-2