如何使用 bash 找到给定进程的顶级父 PID?
假设我运行 ps axf
并且可以看到我的命令的进程树如下所示:
800 ? Ss 0:00 /usr/sbin/sshd
10186 ? Ss 0:00 \_ sshd: yukondude [priv]
10251 ? S 0:00 \_ sshd: yukondude@pts/0
10252 pts/0 Ss 0:00 \_ -bash
10778 pts/0 S 0:00 \_ su -
10785 pts/0 S 0:00 \_ -su
11945 pts/0 R+ 0:00 \_ ps axf
我知道我可以检查 $
当前 shell 的 PID (10785) 或 < code>$PPID 为父 PID (10778)。
但我只想要顶级父 PID,在本例中为 800(SSH 守护进程)。有什么办法可以轻松做到这一点吗?
我从这个SO答案得知我可以递归地检查 /proc/PID/stat
文件中的第四个条目来查找每个进程的父 PID:(
# cut -f4 -d' ' /proc/10785/stat
10778
# cut -f4 -d' ' /proc/10778/stat
10252
# cut -f4 -d' ' /proc/10252/stat
10251
# cut -f4 -d' ' /proc/10251/stat
10186
# cut -f4 -d' ' /proc/10186/stat
800
# cut -f4 -d' ' /proc/800/stat
1
顶级父 PID 将是我到达 init 的 PID,即 1。)
在我编写一个小循环(我什至不确定是否可以在 bash 中使用递归)来执行此操作之前,是否有一个我缺少的更简单的方法?也许只是 /proc
下文件的另一个参数?对这些文件的 grep
没有显示任何明显的信息。
编辑:当然,所有Linux进程的顶级进程是/sbin/init,PID为1。我想要的是之前的父进程的PID:倒数第二个父进程。
Let's say I run ps axf
and I can see that my command's process tree looks like this:
800 ? Ss 0:00 /usr/sbin/sshd
10186 ? Ss 0:00 \_ sshd: yukondude [priv]
10251 ? S 0:00 \_ sshd: yukondude@pts/0
10252 pts/0 Ss 0:00 \_ -bash
10778 pts/0 S 0:00 \_ su -
10785 pts/0 S 0:00 \_ -su
11945 pts/0 R+ 0:00 \_ ps axf
I know I can check $$
for the current shell's PID (10785) or $PPID
for the parent PID (10778).
But I just want the top-level parent PID, which would be 800 (SSH daemon) in this example. Is there any way to do that easily?
I learned from this SO answer that I can recursively check the 4th entry in the /proc/PID/stat
file to find each process's parent PID:
# cut -f4 -d' ' /proc/10785/stat
10778
# cut -f4 -d' ' /proc/10778/stat
10252
# cut -f4 -d' ' /proc/10252/stat
10251
# cut -f4 -d' ' /proc/10251/stat
10186
# cut -f4 -d' ' /proc/10186/stat
800
# cut -f4 -d' ' /proc/800/stat
1
(The top-level parent PID will be the one just before I reach init
's PID, i.e., 1.)
Before I write a little loop (I'm not even sure if you can use recursion in bash) to do this, is there a much more straightforward method that I'm missing? Maybe just another parameter of a file under /proc
? A grep
through those files didn't reveal anything obvious.
Edit: Of course, the top-level process for all Linux processes is /sbin/init with a PID of 1. What I want is the PID of the parent just before that: the penultimate parent.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
如果没有更好的解决方案,这里有一个简单的(递归)脚本来获取您给它的任何进程号的顶级父 PID(如果您省略 PID 参数,则为当前 shell):
只需
source
此脚本并根据需要调用带或不带 PID 参数的top_level_parent_pid
。感谢@Dennis Williamson 对于如何紧凑而高效地编写此脚本提出了许多建议。
Failing a better solution, here's a simple (recursive) script to get the top-level parent PID of any process number you give it (or the current shell if you leave out the PID argument):
Just
source
this script and calltop_level_parent_pid
with or without a PID argument, as appropriate.Thanks to @Dennis Williamson for his many suggestions on how to write this script compactly and efficiently.
Bash 绝对可以做递归。
您可以通过执行以下操作从 stat 文件中检索第四个字段,而无需使用外部
cut
实用程序:如果该命令的名称中可能包含空格,您可以从该命令的末尾开始计数数组(假设字段数量稳定)。如果命令名称中没有空格,这也将起作用。
这是另一种应该避免这些问题的技术(但如果命令名称包含换行符,则可能会失败):
该文件中的第五个字段如下所示:
并且大括号扩展将所有内容都剥离到制表符,只留下数字部分。
Bash can definitely do recursion.
You can retrieve the fourth field from the stat file without using the external
cut
utility by doing something like this:If the command might have space(s) in its name, you can count from the end of the array (assuming that the number of fields is stable). This will also work if there are no spaces in the command's name.
Here's another technique which should avoid those problems (but may fail if the command name contains a newline):
The fifth field in that file looks like:
and the brace expansion strips the everything up to the tab character leaving just the numeric part.
另一个解决方案(来自此处):
Another solution (from here):
迭代版本:
作为两个独立的函数,因为有时您只需要父 PID,有时您需要整个树。
Iterative version:
As two separate functions, because sometimes you want parent PID only, and sometimes you want the whole tree.
我改进了您 (@yukondude) 的递归解决方案,以避免命令名称包含内部字段分隔符 (IFS) 字符(例如空格、制表符和换行符)的问题,这些字符是合法的 Unix 文件名字符。
I improved upon your (@yukondude)'s recursive solution to avoid issues where the command name contains internal field separator (IFS) characters like space, tab, and newline, which are legal Unix filename characters.
OS X 版本,改编自 @albert 和 @yukondude 的回答:
OS X version, adapted from @albert and @yukondude's answers: