Skip to main content
 首页 » 编程设计

python之获取 screen 运行的命令的 pid

2025年05月04日16jiqing9006

我正在开发一个 Minecraft (Bukkit) 服务器管理器。它的 porpuse 只是启动它、停止它、备份它并检查它是否正在运行。最后一个导致了问题。 如果我这样做是为了获取服务器的 pid:

subprocess.Popen(["screen", "-dmS", "minecraft-server", "serverstart.sh"]) 

我得到了 screen 命令的 pid,而不是启动脚本。然而,pid 似乎始终位于启动脚本的 pid 之下,但我认为这是不可靠的。 如何获取java进程的pid?

编辑: 我试过了,但是 ps 返回退出代码 1 并且没有子 pid。我认为这是因为 screen 立即关闭。

check_output(['ps', '--ppid', str(Popen(['screen', '-dmS', 'test']).pid), '--no-headers', '-o', 'pid']) 

请您参考如下方法:

如果你有 screen 的进程 ID(父进程,你可以用 p.pid 假设你使用了 p = Subprocess.Popen(...) ),你可以通过类似的方式获取子进程 ID

ps --ppid <SCREEN_PID> --no-headers -o pid 

还有 psutil.Process(<SCREEN_PID>).get_children()可从 psutil 获得模块可能比解析 ps 的输出更受欢迎,因为(我认为)它解析 /proc直接。

Python的standard os module里面也有一些函数这允许您直接使用进程 ID 做一些事情,但不能获取父进程 ID 或进程组 ID 的子进程 ID。


以下代码:

#!/bin/env python 
 
import subprocess, random, string, re 
import psutil 
 
SERVER_SCRIPT = "./serverstart.sh" 
 
def get_random_key(strlen): 
    return 'K'+''.join(random.choice(string.hexdigits) for x in range(strlen-1)) 
 
def find_screen_pid(name): 
    ph = subprocess.Popen(["screen", "-ls"], stdout=subprocess.PIPE) 
    (stdout,stderr) = ph.communicate() 
    matches = re.search(r'(\d+).%s' % name, stdout, re.MULTILINE) 
    if(matches):  
        pids = matches.groups() 
        if(len(pids) == 1): return int(pids[0]) 
        else: raise Exception("Multiple matching PIDs found: %s" % pids) 
    raise Exception("No matching PIDs found") 
 
def get_child_pids(parent_pid): 
    pp = psutil.Process(parent_pid) 
    return [ int(cp.pid) for cp in pp.get_children()] 
 
# Generate a random screen name, in case you're running multiple server instances 
screenname = "minecraft-server-" + get_random_key(5) 
print("Creating screen session named: %s" % screenname) 
subprocess.Popen(["screen", "-dmS", screenname, SERVER_SCRIPT]).wait() 
 
spid = find_screen_pid(screenname)  # Display some output 
print("Screen PID: %d" % spid) 
cpids = get_child_pids(spid) 
print("Child PIDs: %s" % cpids) 

产生输出:

./screen-pid.py 
Creating screen session named: minecraft-server-K77d1 
Screen PID: 2274 
Child PIDs: [2276] 

您可以使用 cpids[0] 从子 pid 列表访问子 pid .

该脚本简单地生成具有特定名称的 screen 进程,然后找到父进程 ID,并从中找到子进程 ID。

附加到 screen 名称的随机字符在那里,以防您使用同一脚本运行多个实例。如果不是,您可以删除所有这些,但保留它没有任何区别。

查找父进程 ID(解析 screen -ls 的输出)的方法可能不是最好的,您也可以使用 psutils.process_iter() 遍历进程.但这似乎有效。