有没有办法在Python中更改有效的进程名称?

时间:2009-02-19 10:37:12

标签: python process arguments hide ps

我可以更改Python脚本的有效进程名称吗?当我获得系统进程列表时,我想显示一个不同的名称而不是进程的真实名称。在C中我可以设置

strcpy(argv[0],"othername");

但是在Python中

argv[0] = "othername"

似乎不起作用。当我获得进程列表(在我的linux框中使用ps ax)时,真实姓名不会改变。我更喜欢便携式解决方案(或者一个用于posix的解决方案和另一个用于Windows环境的解决方案),如果它存在的话。

提前致谢

9 个答案:

答案 0 :(得分:80)

我最近编写了一个Python模块,以便携式方式更改流程标题:检查https://github.com/dvarrazzo/py-setproctitle

它是PostgreSQL用于执行标题更改的代码的包装器。它目前针对Linux和Mac OS X进行了测试:Windows(功能有限)和BSD移植正在进行中。

编辑:截至2010年7月,该模块与BSD配合使用,在Windows上功能有限,并已移植到Python 3.x.

答案 1 :(得分:50)

实际上你需要在linux上做两件事:从argv[0]修改C(对于ps auxf和朋友)并使用prctl标记调用PR_SET_NAME

绝对没有办法从python本身做第一件事。虽然,您可以通过调用prctl来更改进程名称。

def set_proc_name(newname):
    from ctypes import cdll, byref, create_string_buffer
    libc = cdll.LoadLibrary('libc.so.6')
    buff = create_string_buffer(len(newname)+1)
    buff.value = newname
    libc.prctl(15, byref(buff), 0, 0, 0)

def get_proc_name():
    from ctypes import cdll, byref, create_string_buffer
    libc = cdll.LoadLibrary('libc.so.6')
    buff = create_string_buffer(128)
    # 16 == PR_GET_NAME from <linux/prctl.h>
    libc.prctl(16, byref(buff), 0, 0, 0)
    return buff.value

import sys
# sys.argv[0] == 'python'

# outputs 'python'
get_proc_name()

set_proc_name('testing yeah')

# outputs 'testing yeah'
get_proc_name()

ps auxf之后会显示'python':(。但topps -A会显示新的'测试是'流程名称:)。此外,killallpkill也可以使用新名称。

btw,来自googlecode的procname也会更改argv[0],因此,甚至会更改ps auxf输出。

更新:此答案中发布的解决方案有时在FreeBSD上效果不佳。我现在使用py-setproctitle陈述in this answer一年左右的各种linux和freebsd框。到目前为止没有失败!每个人都应该! :)。它在其主数据库和子进程中使用与PostgreSQL uses几乎相同的代码。

答案 2 :(得分:13)

简单地说,没有可移植的方式。您必须测试系统并使用该系统的首选方法。

此外,我对Windows上的进程名称的含义感到困惑。

你的意思是服务名称?我认为是这样,因为没有别的东西真的有意义(至少对我的非Windows使用大脑)。

如果是这样,您需要使用Tim Golden's WMI interface并在服务上调用.Change方法...至少根据他的tutorial

对于Linux,除了为您设置argv [0]的this poorly packaged module之外,我找不到任何方法。

我甚至不知道这是否适用于BSD变体(它有一个setproctitle系统调用)。我很确定argv [0]不适用于Solaris。

答案 3 :(得分:7)

查看setproctitle

这是一个非常便携的版本,适用于许多平台。

答案 4 :(得分:4)

首先,我不确定C程序中的简单设置argv[0]是否可以改变ps中显示的名称。也许它在一些unixen中确实存在,但我的理解是它不会被期望。

其次,由于Windows特别是非POSIX兼容,因此在POSIX和非POSIX之间只有少数东西是“可移植的”。既然你专门说'ps',我会假设POSIX是你的优先考虑因素,而Windows可能无效。

更重要的是,我对更改argv[0]的理解是,需要调用exec才能进行这些更改。具体来说,exec调用具有可执行文件的路径和单独的argv列表。进行自己的调用允许您打破将可执行文件名放在argv[0]

中的shell约定

您拥有OS library process management,可让您直接访问操作系统库以执行此操作。您应该考虑将脚本分为两部分 - 启动器和“实际工作”。启动器建立运行时环境并执行具有所需参数的实际工作。

在C中,您将自己的流程替换为另一个流程。在Python中,您将使用具有不同argv [0]的新Python解释器替换旧的Python解释器。希望它不会对此犹豫不决。有些程序检查argv [0]来决定他们在做什么。

您还可以使用subprocess.popen来设置所需的参数和可执行文件。然而,在这种情况下,父进程应该在孩子完成时继续收集孩子。父母可能不会做Popen.wait

以外的任何事情

答案 5 :(得分:3)

我对类似问题的回答标记为duplicate

有更简单的(你不需要导入任何libs),但可能不那么优雅。你必须不要使用&#34; env&#34;在shebang线内。

换句话说,这将命名为&#34; python&#34;在进程列表中:

#!/usr/bin/env python

但是这将使用您的脚本名称命名:

#!/usr/bin/python

因此,您可以使用pidof -x scriptnameps -C scriptname

之类的内容找到它

答案 6 :(得分:2)

我发现python-prctl在Linux下运行良好。你必须为Windows找到别的东西。

答案 7 :(得分:0)

如果您只需要支持 Linux 并且只需要更改进程名称,那么您只需将其写入 /proc/self/comm

示例:

import os
import subprocess

print(subprocess.run(['pidof', 'foo'], stdout=subprocess.PIPE,
        universal_newlines=True))
print(subprocess.check_output(['ps', 'p', str(os.getpid()), '-o', 'pid,comm,cmd'],
        universal_newlines=True))

with open(f'/proc/self/comm', 'w') as f:
    f.write('foo')

print(subprocess.check_output(['pidof', 'foo'], universal_newlines=True))
print(subprocess.check_output(['ps', 'p', str(os.getpid()), '-o', 'pid,comm,cmd'],
    universal_newlines=True))

输出:

$ python3 test.py argone argtwo
CompletedProcess(args=['pidof', 'foo'], returncode=1, stdout='')
    PID COMMAND         CMD
2881003 python3 test.py python3 test.py argone argtwo

2881003

    PID COMMAND         CMD
2881003 foo             python3 test.py argone argtwo

注意:在 Linux 上,在 C 程序中,写入 argv[0] 只会更改 /proc/self/cmdline 中的参数和 /proc/self/comm 中的 not。因此,它不会影响 pidoftop COMMAND 列、ps COMMAND 列、普通 pgrep 等。


setproctitle 包支持多个平台,并且 - 在 Linux 上 - 更改命令和参数向量。但是,它是一个 C 扩展。

答案 8 :(得分:-15)

In [1]: import sys

In [2]: print sys.argv[0]
C:\Python25\scripts\ipython.py

In [3]: sys.argv[0] = 'foo'

In [4]: print sys.argv[0]
foo

请注意单个'='符号