ps:如何递归获取给定pid的所有子进程

kyn*_*nan 53 linux unix process ps

如何让给定进程产生的整个进程树显示为树,并且只有该树,即没有其他进程?

输出可能看起来像

 4378 ?        Ss     0:10 SCREEN
 4897 pts/16   Ss     0:00  \_ -/bin/bash
25667 pts/16   S+     0:00  |   \_ git diff
25669 pts/16   S+     0:00  |       \_ less -FRSX
11118 pts/32   Ss+    0:00  \_ -/bin/bash
11123 pts/32   S+     0:00      \_ vi
Run Code Online (Sandbox Code Playgroud)

我无法仅使用ps.

以下给出了所需的结果,但似乎有点涉及:

#!/bin/bash

pidtree() {
  echo -n $1 " "
  for _child in $(ps -o pid --no-headers --ppid $1); do
    echo -n $_child `pidtree $_child` " "
  done
}

ps f `pidtree 4378`
Run Code Online (Sandbox Code Playgroud)

有没有人有更简单的解决方案?

Tru*_*ueY 51

pstree是一个非常好的解决方案,但它有点沉默寡言。我用ps --forest代替。但不是用于PID( -p) 因为它只打印特定进程,而是用于会话 ( -g)。它可以打印出任何ps可以在定义-o选项的花哨 ASCII 艺术树中打印的信息。

所以我对这个问题的建议:

ps --forest -o pid,tty,stat,time,cmd -g 2795
Run Code Online (Sandbox Code Playgroud)

如果该进程不是会话领导者,则必须应用更多技巧:

ps --forest -o pid,tty,stat,time,cmd -g $(ps -o sid= -p 2795)
Run Code Online (Sandbox Code Playgroud)

这首先获取当前进程的会话 id (SID),然后使用该 sid 再次调用 ps。

如果不需要列标题,请在“-o”选项中的每个列定义后添加“=”,例如:

ps --forest -o pid=,tty=,stat=,time=,cmd= -g $(ps -o sid= -p 2795)
Run Code Online (Sandbox Code Playgroud)

示例运行和结果:

$ ps --forest -o pid=,tty=,stat=,time=,cmd= -g $(ps -o sid= -p 30085)
27950 pts/36   Ss   00:00:00 -bash
30085 pts/36   S+   00:00:00  \_ /bin/bash ./loop.sh
31888 pts/36   S+   00:00:00      \_ sleep 5
Run Code Online (Sandbox Code Playgroud)

不幸的是,这不起作用,screen因为它为每个子屏幕和所有孙子 bash 设置了 sid。

要获得一个进程产生的所有进程,需要构建整个树。我为此使用了。首先它构建一个散列数组来包含所有PID => ,child,child.... 最后它调用一个递归函数来提取给定进程的所有子进程。结果被传递给另一个ps以格式化结果。实际的 PID 必须作为参数写入而不是<PID>

ps --forest $(ps -e --no-header -o pid,ppid|awk -vp=<PID> 'function r(s){print s;s=a[s];while(s){sub(",","",s);t=s;sub(",.*","",t);sub("[0-9]+","",s);r(t)}}{a[$2]=a[$2]","$1}END{r(p)}')
Run Code Online (Sandbox Code Playgroud)

对于 SCREEN 进程 (pid=8041),示例输出如下所示:

  PID TTY      STAT   TIME COMMAND
 8041 ?        Ss     0:00 SCREEN
 8042 pts/8    Ss     0:00  \_ /bin/bash
 8092 pts/8    T      0:00      \_ vim test_arg test_server
12473 pts/8    T      0:00      \_ vim
12972 pts/8    T      0:00      \_ vim
Run Code Online (Sandbox Code Playgroud)

  • 如果`ps`有一个过滤器标志选项只是为了过滤PID的所有后代,那么这看起来应该很简单。 (2认同)

Ero*_*oen 30

pstree ${pid}
Run Code Online (Sandbox Code Playgroud)

${pid}父进程的pid在哪里。

在 Gentoo Linux 上,pstree位于包“psmisc”中,显然位于http://psmisc.sourceforge.net/

  • 谢谢,应该提到我看过`pstree`,但错过了更详细的输出格式。但是,`pstree -p &lt;pid&gt;` 至少会打印相当接近的 pid。 (10认同)
  • 我也有这个问题,我需要递归地收集所有子 pid,但我只需要 pid,所以我必须`sed`所有这些..嗯,这有效:) `pstree -pn 4008 |grep -o "([ [:digit:]]*)" |grep -o "[[:digit:]]*"` (3认同)

小智 14

这是我立即运行的版本(因为ps只执行一次)。适用于 bash 和 zsh。

pidtree() (
    [ -n "$ZSH_VERSION"  ] && setopt shwordsplit
    declare -A CHILDS
    while read P PP;do
        CHILDS[$PP]+=" $P"
    done < <(ps -e -o pid= -o ppid=)

    walk() {
        echo $1
        for i in ${CHILDS[$1]};do
            walk $i
        done
    }

    for i in "$@";do
        walk $i
    done
)
Run Code Online (Sandbox Code Playgroud)


小智 5

ps -H -g "$pid" -o comm

本身不添加树,它只是进程列表。

例如给出

COMMAND
bash
  nvim
    python
Run Code Online (Sandbox Code Playgroud)