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

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


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

编辑:
我试过了,但是ps返回的退出代码为1,没有子pid。我认为这是因为屏幕突然关闭了。

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

最佳答案

如果您具有屏幕的进程ID(父进程,假设您使用p.pid,则可以使用p = Subprocess.Popen(...)访问该父进程),则可以通过以下方式获取子进程ID:

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


psutil模块中还提供了psutil.Process(<SCREEN_PID>).get_children(),它可能比解析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
创建名为:minecraft-server-K77d1的屏幕会话
屏幕PID:2274
子PID:[2276]


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

该脚本仅使用特定名称生成屏幕进程,然后找到父进程ID,并从中找到子进程ID。

如果您使用同一脚本运行多个实例,则在屏幕名称后附加了随机字符。如果不是,则可以删除所有这些内容,但是保留它没有任何区别。

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

关于python - 获取屏幕显示的命令的pid,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/15840738/

10-12 18:26
查看更多