1

Minecraft (Bukkit) サーバー マネージャーを開発しています。ポーパスは、起動、停止、バックアップ、および実行されているかどうかを確認するだけです。最後の 1 つが問題を引き起こします。サーバーのpidを取得するためにこれが好きなら:

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

起動スクリプトではなく、画面コマンドの pid を取得します。ただし、pidは常に起動スクリプトのpidの下にあるようですが、これは信頼できないと思います。Javaプロセスのpidを取得するにはどうすればよいですか?

編集:これを試しましたが、ps は終了コード 1 で戻り、子 pid はありません。これは、画面がすぐに閉じてしまうためだと思います。

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

3 に答える 3

4

p.pid画面のプロセス ID (を使用したと仮定してアクセスできる親プロセス) がある場合はp = Subprocess.Popen(...)、次のような方法で子プロセス ID を取得できます。

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

(私が思うに)直接解析するため、psの出力を解析するよりも好ましいかもしれないpsutilモジュールからもpsutil.Process(<SCREEN_PID>).get_children()利用できます。/proc

Python の標準 os モジュール内には、プロセス 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]

を使用して、子 pid リストから子 pid にアクセスできますcpids[0]

このスクリプトは、特定の名前で screen プロセスを生成し、親プロセス ID を見つけ、そこから子プロセス ID を見つけます。

同じスクリプトを使用して複数のインスタンスを実行している場合に備えて、スクリーン名にランダムな文字が追加されています。そうでない場合は、それをすべて削除できますが、そのままにしておくことに違いはありません。

親プロセス ID を見つける方法 ( の出力を解析するscreen -ls) はおそらく最善ではありませんpsutils.process_iter()。しかし、これはうまくいくようです。

于 2013-04-05T18:41:32.293 に答える
2

画面で実行されているプロセスの PID が必要であると仮定して、このサイトの別の質問で答えました。その回答の内容は次のとおりです。

次のように、画面セッションの PID を取得できます。

$ screen -ls
There are screens on:
        1934.foo_Server         (01/25/15 15:26:01)     (Detached)
        1876.foo_Webserver      (01/25/15 15:25:37)     (Detached)
        1814.foo_Monitor        (01/25/15 15:25:13)     (Detached)
3 Sockets in /var/run/screen/S-ubuntu.

foo_Monitorscreen セッションで Bash で実行されているプログラムの PID が必要だとします。foo_Monitorscreen セッションの PID を使用しbashて、既知の PID の PPID (親 PID) を検索して、その中で実行されているセッションの PID を取得します。

$ ps -el | grep 1814 | grep bash
F S   UID   PID  PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
0 S  1000  1815  1814  0  80   0 -  5520 wait   pts/1    00:00:00 bash

bashセッションの PID だけを取得します。

$ ps -el | grep 1814 | grep bash | awk '{print $4}'
1815

次に、そのPIDを持つプロセスが必要です。コマンドをネストするだけで、今度は-vフラグ onを使用して、 bashではないgrep bashプロセスを取得します。

echo $(ps -el | grep $(ps -el | grep 1814 | grep bash | awk '{print $4}') | grep -v bash | awk '{print $4}')
23869

1814 を実際の PID または画面セッションに置き換えるだけです。

echo $(ps -el | grep $(ps -el | grep SCREEN_SESSION_PID | grep bash | awk '{print $4}') | grep -v bash | awk '{print $4}')
于 2015-02-08T14:45:37.883 に答える
1

Java コマンドを、pid を取得して返すシェル スクリプトにラップする必要があります。例については、 http://ss64.org/viewtopic.php?id=1495を参照してください。

于 2013-04-05T18:21:07.910 に答える