社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Python

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

未闻Code • 1 年前 • 151 次点击  

本文旨在解决 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 杀死进程,强制杀死使用 kill -9 ,这里涉及到 linux signals,明天专门写一篇 linux signals 来阐述其中原理

Windows 使用 taskkill /T /F /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”,备注“粉丝群”(谢绝广告党,非诚勿扰!)

Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/171996
 
151 次点击