有没有办法在 Python 中更改有效进程名称?
- 2025-03-20 08:47:00
- admin 原创
- 46
问题描述:
我可以更改 Python 脚本的有效进程名称吗?我想在获取系统进程列表时显示不同的名称而不是进程的真实名称。在 CI 中可以设置
strcpy(argv[0],"othername");
但是在 Python 中
argv[0] = "othername"
似乎不起作用。当我获取进程列表时(ps ax
在我的 Linux 机器中),真实名称没有改变。如果存在的话,我更喜欢可移植的解决方案(或者一个解决方案适用于 posix,另一个适用于 windows 环境)。
解决方案 1:
我最近编写了一个 Python 模块,以可移植的方式更改进程标题:检查https://github.com/dvarrazzo/py-setproctitle
它是 PostgreSQL 用于执行标题更改的代码的包装器。它目前已针对 Linux 和 Mac OS X 进行了测试:Windows(功能有限)和 BSD 移植正在进行中。
编辑:截至 2010 年 7 月,该模块可在 BSD 上运行,在 Windows 上的功能有限,并且已移植到 Python 3.x。
解决方案 2:
实际上在 Linux 上你需要两样东西:修改argv[0]
自C
(forps 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”:(。但是top
和ps -A
将显示新的“testing yeah”进程名称:)。此外killall
和pkill
将使用新名称。
顺便说一句,googlecode 的 procname 也会改变argv[0]
,因此甚至会改变ps auxf
输出。
更新:此答案中发布的解决方案有时在 FreeBSD 上无法很好地运行。我现在在各种 Linux 和 FreeBSD 机器上使用这个答案中所述的py-setproctitle已有一年左右了。到目前为止没有失败!每个人都应该这样做!:)。它使用的代码与PostgreSQL在其主数据库和子进程中使用的代码几乎相同。
解决方案 3:
查看setproctitle包
这是一个相当便携的版本并且适用于许多平台。
pip install setproctitle
import setproctitle
setproctitle.setproctitle('new proc title as seen in top')
解决方案 4:
简而言之,没有可移植的方法。您必须针对系统进行测试,并使用该系统的首选方法。
此外,我对您所说的 Windows 上的进程名称的含义感到困惑。
你是指服务名称吗?我猜是的,因为其他的都没有任何意义(至少对我这个不使用 Windows 的人来说)。
如果是这样,您需要使用Tim Golden 的 WMI 接口并在服务上调用 .Change 方法……至少根据他的教程。
对于 Linux,我发现除了这个为您设置 argv[0] 的封装不良的模块之外,其他所有方法都不起作用。
我甚至不知道这是否适用于 BSD 变体(它确实有一个 setproctitle 系统调用)。我非常确定 argv[0] 不会在 Solaris 上运行。
解决方案 5:
我对标记为重复的类似问题的回答:
有一种更简单(不需要导入任何库)但可能不太优雅的方法。您必须不要在 shebang 行中使用“env”。
换句话说,这将在进程列表中被命名为“python”:
#!/usr/bin/env python
但这将以你的脚本名称命名:
#!/usr/bin/python
因此,您可以使用类似pidof -x scriptname
或ps -C scriptname
解决方案 6:
首先,我不确定简单地argv[0]
在 C 程序中设置是否可以更改 中显示的名称ps
。也许在某些 unixen 中可以,但我的理解是它不应该这样做。
其次,由于 Windows 明确地不兼容 POSIX,因此只有少数东西可以在 POSIX 和非 POSIX 之间“移植”。由于您明确地提到了“ps”,因此我假设 POSIX 是您的首选,而 Windows 可能无法工作。
更重要的是,我对更改的理解argv[0]
是,它需要调用 来exec
进行这些更改。具体来说,exec
调用既有可执行文件的路径,也有单独的argv
列表。进行自己的调用可以打破将可执行文件名称放在 中的 shell 惯例argv[0]
。
您有OS 库进程管理,它可让您直接访问 OS 库来执行此操作。您应该考虑将脚本分为两部分 - 启动程序和“实际工作”。启动程序建立运行时环境并使用所需参数执行实际工作。
在 C 中,您将用另一个进程替换您自己的进程。在 Python 中,您将用具有不同 argv[0] 的新解释器替换旧的 Python 解释器。希望它不会因此而犹豫不决。有些程序会检查 argv[0] 来决定它们在做什么。
您还可以使用subprocess.popen来设置所需的参数和可执行文件。但是,在这种情况下,父进程应该在子进程完成后继续收集子进程。父进程可能只做一件事Popen.wait
解决方案 7:
我发现python-prctl在 Linux 下运行得很好。您必须为 Windows 寻找其他工具。
解决方案 8:
如果您只需要支持 Linux 并且只需要更改进程名称,那么您只需将其写入即可/proc/self/comm
。
例子:
#!/usr/bin/python3
import os
import subprocess
print(f'my pid: {os.getpid()}')
r = subprocess.run(['pidof', 'foo'], stdout=subprocess.PIPE, text=True)
print(f'pidof foo: {r}')
r = subprocess.check_output(['ps', 'p', str(os.getpid()), '-o', 'pid,comm,cmd'], text=True)
print(f'ps -p {os.getpid()} ...:
{r}')
print('Setting comm to foo ...')
with open(f'/proc/self/comm', 'w') as f:
f.write('foo')
r = subprocess.check_output(['pidof', '-w', 'foo'], text=True)
print(f'pidof -w foo: {r}')
r = subprocess.check_output(['pgrep', '^foo$'], text=True)
print(f"pgrep '^foo$': {r}")
r = subprocess.check_output(['ps', 'p', str(os.getpid()), '-o', 'pid,comm,cmd'], text=True)
print(f'ps -p ...:
{r}')
r = subprocess.run(['pidof', 'foo'], stdout=subprocess.PIPE, text=True)
print(f'pidof foo: {r}')
r = subprocess.run(['pidof', '-x', 'foo'], stdout=subprocess.PIPE, text=True)
print(f'pidof -x foo: {r}')
输出(在 Fedora 39 上):
$ python3 test.py argone argtwo
my pid: 528627
pidof foo: CompletedProcess(args=['pidof', 'foo'], returncode=1, stdout='')
ps -p 528627 ...:
PID COMMAND CMD
528627 python3 python3 test.py argone argtwo
Setting comm to foo ...
pidof -w foo: 528627
pgrep '^foo$': 528627
ps -p ...:
PID COMMAND CMD
528627 foo python3 test.py argone argtwo
pidof foo: CompletedProcess(args=['pidof', 'foo'], returncode=1, stdout='')
pidof -x foo: CompletedProcess(args=['pidof', '-x', 'foo'], returncode=1, stdout='')
注意:在 Linux 上,在 C 程序中,写入argv[0]
只会更改中的参数/proc/self/cmdline
,而不会更改中的参数/proc/self/comm
。因此,它不会影响top
COMMAND 列、ps
COMMAND 列、纯文本pgrep
等。
setproctitle包支持多种平台,在 Linux 上可更改命令和参数向量。不过,它是一个 C 扩展。
解决方案 9:
如果您想使用内置库,您也可以使用multiprocessing
。
import multiprocessing
if __name__ == '__main__':
current_process = multiprocessing.current_process()
current_process.name = 'NewProcessName'
print(f"The process name is now: {current_process.name}")
解决方案 10:
Windows 上的一个超级技巧是复制 python.exe,将其重命名为 process_name.exe,然后使用重命名的 python 调用你的脚本。
这是一个超级黑客,但由于 Windows 上没有简单的解决方案,并且如果只需要快速完成一个脚本就可以监控它,那么这是一个公平的选择。
理论上它甚至可以编写脚本...超级黑客!?
解决方案 11:
In [1]: import sys
In [2]: print sys.argv[0]
C:Python25scriptsipython.py
In [3]: sys.argv[0] = 'foo'
In [4]: print sys.argv[0]
foo
注意单个“=”符号
扫码咨询,免费领取项目管理大礼包!