Finding the command for a specific PID in Linux from Python
I’d like to know if it’s possible to find out the «command» that a PID is set to. When I say command, I mean what you see in the last column when you run the command «top» in a linux shell. I’d like to get this information from Python somehow when I have a specific PID. Any help would be great. Thanks.
7 Answers 7
Using a /proc files has a disadvantage of lower portability, which may or may not be a concern. Here’s how you can use the standard shell command for that
Note the two -w options that instructs ps to not truncate the output (which it does by default)
Reading its output from python is as simple as calling a single function subprocess.check_output() documented here.
ps works by reading the virtual files in /proc. So much for the well-defined POSIX interface (which one was that, anyway?).
Listen, I would have marked you both as correct answers but I couldn’t. Pavel’s answer just seemed to be more of what I was looking for but the answer given for DigitalRoss was great too. Upvotes for both.
@Nick Stinemates, @Michael Foukarakis. Hey, I know how ps works (yes, it indeed reads files in /proc ). But when instead of /proc they’ll invent /foobar system, you’ll have to rewrite your program. Anyway, maybe I’ve been braindamaged by working in LSB workgroup, but you really should stick to standards where it’s enough for you—which is the case under consideration.
This command will output the command line args, but separate them with spaces. If you’re trying to split the arguments back into a list of strings, you won’t be able to differentiate between args, and args with spaces. (Which you can do with /proc/$PID/cmdline )
An interesting Python package is psutil.
For example, to get the command for a specific PID:
import psutil pid = 1234 # The pid whose info you're looking for p = psutil.Process(pid) print(p.cmdline())
The last line will print something like [‘/usr/bin/python’, ‘main.py’] .
A more robust way to get this information, being careful if the pid represents a process no longer running:
import psutil pid = 1234 # The pid whose info you're looking for if pid in psutil.get_pid_list(): p = psutil.Process(pid) print(p.cmdline())
Look in /proc/$PID/cmdline
Look in /proc/$PID/cmdline , and then os.readlink() on /proc/$PID/exe .
/proc/$PID/cmdline is not necessarily going to be correct, as a program can change its argument vector or it may not contain a full path. Three examples of this from my current process list are:
- avahi-daemon: chroot helper
- qmgr -l -t fifo -u
- /usr/sbin/postgrey —pidfile=/var/run/postgrey.pid —daemonize —inet=127.0.0.1:60000 —delay=55
That first one is obvious — it’s not a valid path or program name. The second is just an executable with no path name. The third looks ok, but that whole command line is actually in argv[0] , with spaces separating the arguments. Normally you should have NUL separated arguments.
All this goes to show that /proc/$PID/cmdline (or the ps(1) output) is not reliable.
However, nor is /proc/$PID/exe . Usually it is a symlink to the executable that is the main text segment of the process. But sometimes it has » (deleted) » after it if the executable is no longer in the filesystem.
Also, the program that is the text segment is not always what you want. For instance, /proc/$PID/exe from that /usr/sbin/postgrey example above is /usr/bin/perl . This will be the case for all interpretted scripts (#!).
I settled on parsing /proc/$PID/cmdline — taking the first element of the vector, and then looking for spaces in that, and taking all before the first space. If that was an executable file — I stopped there. Otherwise I did a readlink(2) on /proc/$PID/exe and removed any » (deleted) » strings on the end. That first part will fail if the executable filename actually has spaces in it. There’s not much you can do about that.
BTW. The argument to use ps(1) instead of /proc/$PID/cmdline does not apply in this case, since you are going to fall back to /proc/$PID/exe . You will be dependent on the /proc filesystem, so you may as well read it with read(2) instead of pipe(2), fork(2), execve(2), readdir(3). write(2), read(2). While ps and /proc/$PID/cmdline may be the same from the point of view of lines of python code, there’s a whole lot more going on behind the scenes with ps.
Process list on Linux via Python
IMO looking at the /proc filesystem is less nasty than hacking the text output of ps .
import os pids = [pid for pid in os.listdir('/proc') if pid.isdigit()] for pid in pids: try: print open(os.path.join('/proc', pid, 'cmdline'), 'rb').read().split('\0') except IOError: # proc has already terminated continue
You will have to surround the read() call with a try/except block as a pid returned from reading os.listdir(‘/proc’) may no longer exist by the time you read the cmdline.
Watch out: the command line is terminated by 0x00. Whitespaces are also replaced with the same character.
Just use psutil — it does all this through a nice Pythonic interface and is portable if you ever want to run on a non-Linux server.
You could use psutil as a platform independent solution!
import psutil psutil.pids() [1, 2, 3, 4, 5, 6, 7, 46, 48, 50, 51, 178, 182, 222, 223, 224, 268, 1215, 1216, 1220, 1221, 1243, 1244, 1301, 1601, 2237, 2355, 2637, 2774, 3932, 4176, 4177, 4185, 4187, 4189, 4225, 4243, 4245, 4263, 4282, 4306, 4311, 4312, 4313, 4314, 4337, 4339, 4357, 4358, 4363, 4383, 4395, 4408, 4433, 4443, 4445, 4446, 5167, 5234, 5235, 5252, 5318, 5424, 5644, 6987, 7054, 7055, 7071]
It’s not completely platform independent — on OSX you can run into AccessDenied errors: groups.google.com/forum/?fromgroups=#!topic/psutil/bsjpawhiWms
@amos kinda makes sense — you’d want to have privileges in place first before reaching out to information about processes. Thanks for the hint.
The sanctioned way of creating and using child processes is through the subprocess module.
import subprocess pl = subprocess.Popen(['ps', '-U', '0'], stdout=subprocess.PIPE).communicate()[0] print pl
The command is broken down into a python list of arguments so that it does not need to be run in a shell (By default the subprocess.Popen does not use any kind of a shell environment it just execs it). Because of this we cant simply supply ‘ps -U 0’ to Popen.
You can use a third party library, such as PSI:
PSI is a Python package providing real-time access to processes and other miscellaneous system information such as architecture, boottime and filesystems. It has a pythonic API which is consistent accross all supported platforms but also exposes platform-specific details where desirable.
PSI was last updated in 2009, whereas psutil was updated this month (Nov 2015) — seems like psutil is a better bet.
I would use the subprocess module to execute the command ps with appropriate options. By adding options you can modify which processes you see. Lot’s of examples on subprocess on SO. This question answers how to parse the output of ps for example:)
You can, as one of the example answers showed also use the PSI module to access system information (such as the process table in this example).
from psutil import process_iter from termcolor import colored names = [] ids = [] x = 0 z = 0 k = 0 for proc in process_iter(): name = proc.name() y = len(name) if y>x: x = y if y
Welcome to StackOverflow. While this code may solve the question, including an explanation of how and why this solves the problem would really help to improve the quality of your post, and probably result in more up-votes. Remember that you are answering the question for readers in the future, not just the person asking now. Please edit your answer to add explanations and give an indication of what limitations and assumptions apply.
This code is poorly written, needlessly complex, and unpythonic. It is not a good example of how to achieve this.
How to check if there exists a process with a given pid in Python?
Is there a way to check to see if a pid corresponds to a valid process? I'm getting a pid from a different source other than from os.getpid() and I need to check to see if a process with that pid doesn't exist on the machine. I need it to be available in Unix and Windows. I'm also checking to see if the PID is NOT in use.
Windows is a non-standard OS. These kinds of things are NOT portable. Knowing you cannot have both, which is your priority? Pick one as a priority and edit the question.
@Piotr Dobrogost: Can you provide code that handles POSIX standard unix and non-POSIX standard Windows? If so, please provide an answer that (a) solves the problem and (b) makes it clear that Windows is somehow compliant with the POSIX standard.
@PiotrDobrogost I think S.Lott's remark was more about implementation details and API support than market share.
Windows certainly has less in common with other popular OSes than the rest do with each other. (Anybody who does web development may liken it to a similarly infamous Microsoft product.) But in response to @S.Lott: I rarely write Python code for Windows that's not supposed to also work on Linux, OSX, BSD, etc, so I honestly don't think 'pick on as a priority' is helpful advice, especially since Python abstracts platform differences away as much as practicable.
15 Answers 15
Sending signal 0 to a pid will raise an OSError exception if the pid is not running, and do nothing otherwise.
import os def check_pid(pid): """ Check For the existence of a unix pid. """ try: os.kill(pid, 0) except OSError: return False else: return True
Works for sure in linux and OSX, I can't speak for Windows. It does not kill the process in the sense that you are asking, it sends signal 0, which is basically "Are you running?".
To be complete, you should also check for the error number to make sure it is 3 (catch the exception and check for first arg). This is important if the target process exists but you don't have permission to send signal (for whatever reason).
os.kill is supported on Windows, but os.kill(pid, 0) is the same as os.kill(pid, signal.CTRL_C_EVENT) which may terminate the process (or fail). I get an OSError where errno==EINVAL when I try this on a subprocess.
Have a look at the psutil module:
psutil (python system and process utilities) is a cross-platform library for retrieving information on running processes and system utilization (CPU, memory, disks, network) in Python. [. ] It currently supports Linux, Windows, OSX, FreeBSD and Sun Solaris, both 32-bit and 64-bit architectures, with Python versions from 2.6 to 3.4 (users of Python 2.4 and 2.5 may use 2.1.3 version). PyPy is also known to work.
It has a function called pid_exists() that you can use to check whether a process with the given pid exists.
import psutil pid = 12345 if psutil.pid_exists(pid): print("a process with pid %d exists" % pid) else: print("a process with pid %d does not exist" % pid)
How to check which specific processes (Python scripts) are running?
Using the command 'top' I can see 2 python scripts are running. However, how do I check their names or directory/location? I want to identify them so I can see what is running properly and what isn't.
lsof -p $PID would be a good start. $PID can also be a comma-delimited list of PIDs. Also, tons of data will be exposed in /proc/$PID/ .
3 Answers 3
You can get a list of python processes using pgrep :
This, however, does not list the whole command line. If you have a recent version of pgrep you can use -a to do this:
Otherwise, you can use /proc :
IFS=" " read -ra pids < <(pgrep -f python) for pid in "$"; do printf '%d: ' "$pid" tr '\0' ' ' < "/proc/$pid/cmdline" echo done
I usually use ps -fA | grep python to see what processes are running.
This will give you results like the following:
UID PID PPID C STIME TTY TIME BIN CMD user 3985 3960 0 19:46 pts/4 00:00:07 path/to/python python foo.py
The CMD will show you what python scripts you have running, although it won't give you the directory of the script.
import psutil def check_process_status(process_name): """ Return status of process based on process name. """ process_status = [ proc for proc in psutil.process_iter() if proc.name() == process_name ] if process_status: for current_process in process_status: print("Process id is %s, name is %s, staus is %s"%(current_process.pid, current_process.name(), current_process.status())) else: print("Process name not valid", process_name)
You must log in to answer this question.
Related
Hot Network Questions
Subscribe to RSS
To subscribe to this RSS feed, copy and paste this URL into your RSS reader.
Site design / logo © 2023 Stack Exchange Inc; user contributions licensed under CC BY-SA . rev 2023.7.14.43533
Linux is a registered trademark of Linus Torvalds. UNIX is a registered trademark of The Open Group.
This site is not affiliated with Linus Torvalds or The Open Group in any way.
By clicking “Accept all cookies”, you agree Stack Exchange can store cookies on your device and disclose information in accordance with our Cookie Policy.