Is there a way to change effective process name in Python?
Question:
Can I change effective process name of a Python script? I want to show a different name instead of the real name of the process when I get the system process list. In C I can set
strcpy(argv[0],"othername");
But in Python
argv[0] = "othername"
doesn’t seem to work. When i get process list (with ps ax
in my linux box) the real name doesn’t change. I prefer a portable solution (or else one solution for posix and another for windows environments), if it exists.
Answers:
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
Note the single ‘=’ sign
First, I’m not sure that simply settings argv[0]
in a C program portably changes the name shown in ps
. Maybe it does in some unixen, but my understanding is that it’s not expected to.
Second, since Windows is specifically non-POSIX compliant, only a few things are “portable” between POSIX and non-POSIX. Since you specifically say ‘ps’, I’ll assume that POSIX is your priority and Windows may not work.
More importantly, my understanding of changing argv[0]
is that it requires a call to exec
to make these changes. Specifically, the exec
call has both a path to an executable and a separate argv
list. Making your own call allows you to break the shell convention of putting the executable name in argv[0]
.
You have OS library process management which gives you direct access to the OS library for doing this. You should consider breaking your script into two parts — a starter and the “real work”. The starter establishes the run-time environment and exec’s the real work with the desired parameters.
In C, you’re replacing your own process with another. In Python, you’re replacing the old Python interpreter with a new one that has a different argv[0]. Hopefully, it won’t balk at this. Some programs check argv[0] to decide what they’re doing.
You also have subprocess.popen that you can use to set your desired args and executable. In this case, however, the parent process should lingers around to collect the child when the child finishes. The parent may not be doing anything more than a Popen.wait
Simply put, there’s no portable way. You’ll have to test for the system and use the preferred method for that system.
Further, I’m confused about what you mean by process names on Windows.
Do you mean a service name? I presume so, because nothing else really makes any sense (at least to my non-Windows using brain).
If so, you need to use Tim Golden’s WMI interface and call the .Change method on the service… at least according to his tutorial.
For Linux none of the methods I found worked except for this poorly packaged module that sets argv[0] for you.
I don’t even know if this will work on BSD variants (which does have a setproctitle system call). I’m pretty sure argv[0] won’t work on Solaris.
actually you need 2 things on linux: modify argv[0]
from C
(for ps auxf
and friends) and call prctl
with PR_SET_NAME
flag.
There is absolutely no way to do first piece from python itself. Although, you can just change process name by calling 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
will show just ‘python’ after that :(. But top
and ps -A
will show new ‘testing yeah’ process name :). Also killall
and pkill
will work with new name.
btw, procname from googlecode also changes argv[0]
, thus, even, changes ps auxf
output.
UPDATE: The solution posted in this answer does not play nice sometimes on FreeBSD. I’m now using py-setproctitle stated in this answer for a year or so on various linux and freebsd boxes. No fails so far! Everybody should too! :). It uses almost the same code as PostgreSQL uses in its main database and child processes.
I’ve recently written a Python module to change the process title in a portable way: check https://github.com/dvarrazzo/py-setproctitle
It is a wrapper around the code used by PostgreSQL to perform the title change. It is currently tested against Linux and Mac OS X: Windows (with limited functionality) and BSD portings are on the way.
Edit: as of July 2010, the module works with BSD and with limited functionality on Windows, and has been ported to Python 3.x.
Have a look on setproctitle package
This is quite a portable version and works on many platforms.
pip install setproctitle
import setproctitle
setproctitle.setproctitle('new proc title as seen in top')
I have found python-prctl to work very well under Linux. You will have to find something else for Windows.
My answer to similar question marked as duplicate:
There is simplier (you don’t need import any libs) but maybe not so elegant way. You have to do not use “env” inside the shebang line.
In other words, this will be named as “python” in process list:
#!/usr/bin/env python
But this will be named with your scriptname:
#!/usr/bin/python
So you’ll be able to find it with something like pidof -x scriptname
or ps -C scriptname
If you only need to support Linux and you just need to change the process name then you can simply write it to /proc/self/comm
.
Example:
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))
Output:
$ 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
NB: On Linux, in a C program, writing to argv[0]
just changes the argument in /proc/self/cmdline
and not in /proc/self/comm
. Thus, it doesn’t affect pidof
, the top
COMMAND column, the ps
COMMAND column, plain pgrep
etc.
The setproctitle package supports multiple platforms and – on Linux – changes both the command and the argument vector. However, it’s a C extension.
One super hack on windows is to copy python.exe, rename it to process_name.exe, call your script using the renamed python.
Its a super hacky, but since there is not easy solution on windows and if one just needs to get it done quickly for that one single script to be able to monitor it, its a fair option.
In theory it could even be scripted… super duper hack!?
Can I change effective process name of a Python script? I want to show a different name instead of the real name of the process when I get the system process list. In C I can set
strcpy(argv[0],"othername");
But in Python
argv[0] = "othername"
doesn’t seem to work. When i get process list (with ps ax
in my linux box) the real name doesn’t change. I prefer a portable solution (or else one solution for posix and another for windows environments), if it exists.
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
Note the single ‘=’ sign
First, I’m not sure that simply settings argv[0]
in a C program portably changes the name shown in ps
. Maybe it does in some unixen, but my understanding is that it’s not expected to.
Second, since Windows is specifically non-POSIX compliant, only a few things are “portable” between POSIX and non-POSIX. Since you specifically say ‘ps’, I’ll assume that POSIX is your priority and Windows may not work.
More importantly, my understanding of changing argv[0]
is that it requires a call to exec
to make these changes. Specifically, the exec
call has both a path to an executable and a separate argv
list. Making your own call allows you to break the shell convention of putting the executable name in argv[0]
.
You have OS library process management which gives you direct access to the OS library for doing this. You should consider breaking your script into two parts — a starter and the “real work”. The starter establishes the run-time environment and exec’s the real work with the desired parameters.
In C, you’re replacing your own process with another. In Python, you’re replacing the old Python interpreter with a new one that has a different argv[0]. Hopefully, it won’t balk at this. Some programs check argv[0] to decide what they’re doing.
You also have subprocess.popen that you can use to set your desired args and executable. In this case, however, the parent process should lingers around to collect the child when the child finishes. The parent may not be doing anything more than a Popen.wait
Simply put, there’s no portable way. You’ll have to test for the system and use the preferred method for that system.
Further, I’m confused about what you mean by process names on Windows.
Do you mean a service name? I presume so, because nothing else really makes any sense (at least to my non-Windows using brain).
If so, you need to use Tim Golden’s WMI interface and call the .Change method on the service… at least according to his tutorial.
For Linux none of the methods I found worked except for this poorly packaged module that sets argv[0] for you.
I don’t even know if this will work on BSD variants (which does have a setproctitle system call). I’m pretty sure argv[0] won’t work on Solaris.
actually you need 2 things on linux: modify argv[0]
from C
(for ps auxf
and friends) and call prctl
with PR_SET_NAME
flag.
There is absolutely no way to do first piece from python itself. Although, you can just change process name by calling 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
will show just ‘python’ after that :(. But top
and ps -A
will show new ‘testing yeah’ process name :). Also killall
and pkill
will work with new name.
btw, procname from googlecode also changes argv[0]
, thus, even, changes ps auxf
output.
UPDATE: The solution posted in this answer does not play nice sometimes on FreeBSD. I’m now using py-setproctitle stated in this answer for a year or so on various linux and freebsd boxes. No fails so far! Everybody should too! :). It uses almost the same code as PostgreSQL uses in its main database and child processes.
I’ve recently written a Python module to change the process title in a portable way: check https://github.com/dvarrazzo/py-setproctitle
It is a wrapper around the code used by PostgreSQL to perform the title change. It is currently tested against Linux and Mac OS X: Windows (with limited functionality) and BSD portings are on the way.
Edit: as of July 2010, the module works with BSD and with limited functionality on Windows, and has been ported to Python 3.x.
Have a look on setproctitle package
This is quite a portable version and works on many platforms.
pip install setproctitle
import setproctitle
setproctitle.setproctitle('new proc title as seen in top')
I have found python-prctl to work very well under Linux. You will have to find something else for Windows.
My answer to similar question marked as duplicate:
There is simplier (you don’t need import any libs) but maybe not so elegant way. You have to do not use “env” inside the shebang line.
In other words, this will be named as “python” in process list:
#!/usr/bin/env python
But this will be named with your scriptname:
#!/usr/bin/python
So you’ll be able to find it with something like pidof -x scriptname
or ps -C scriptname
If you only need to support Linux and you just need to change the process name then you can simply write it to /proc/self/comm
.
Example:
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))
Output:
$ 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
NB: On Linux, in a C program, writing to argv[0]
just changes the argument in /proc/self/cmdline
and not in /proc/self/comm
. Thus, it doesn’t affect pidof
, the top
COMMAND column, the ps
COMMAND column, plain pgrep
etc.
The setproctitle package supports multiple platforms and – on Linux – changes both the command and the argument vector. However, it’s a C extension.
One super hack on windows is to copy python.exe, rename it to process_name.exe, call your script using the renamed python.
Its a super hacky, but since there is not easy solution on windows and if one just needs to get it done quickly for that one single script to be able to monitor it, its a fair option.
In theory it could even be scripted… super duper hack!?