优雅地获取后代进程列表

STe*_*yaK 28 process ps

我想获得从$pid. 这是我想出的最简单的方法:

pstree -p $pid | tr "\n" " " |sed "s/[^0-9]/ /g" |sed "s/\s\s*/ /g"
Run Code Online (Sandbox Code Playgroud)

是否有任何命令或任何更简单的方法来获取所有后代进程的完整列表?

Jan*_*der 20

下面更简单一些,并且具有忽略命令名称中的数字的额外优势:

pstree -p $pid | grep -o '([0-9]\+)' | grep -o '[0-9]\+'
Run Code Online (Sandbox Code Playgroud)

或者使用 Perl:

pstree -p $pid | perl -ne 'print "$1\n" while /\((\d+)\)/g'
Run Code Online (Sandbox Code Playgroud)

我们正在寻找括号内的数字,这样我们就不会,例如,当我们遇到gif2png(3012). 但是,如果命令名称包含括号中的数字,则所有赌注都将关闭。只有到目前为止文本处理可以带你。

所以我也认为流程组是可行的方法。如果你想让一个进程在它自己的进程组中运行,你可以使用 Debian 软件包“daemontools”中的“pgrphack”工具:

pgrphack my_command args
Run Code Online (Sandbox Code Playgroud)

或者你可以再次转向 Perl:

perl -e 'setpgid or die; exec { $ARGV[0] } @ARGV;' my_command args
Run Code Online (Sandbox Code Playgroud)

这里唯一需要注意的是进程组不嵌套,因此如果某个进程正在创建自己的进程组,则其子进程将不再位于您创建的组中。


小智 10

descendent_pids() {
    pids=$(pgrep -P $1)
    echo $pids
    for pid in $pids; do
        descendent_pids $pid
    done
}
Run Code Online (Sandbox Code Playgroud)


max*_*zig 7

还有正确性的问题。单纯地解析 的输出pstree是有问题的,原因如下:

  • pstree 显示 PID线程的 id(名称显示在花括号中)
  • 命令名称可能包含花括号、括号中的数字,这使得可靠的解析变得不可能

如果您安装了 Python 并psutil安装了软件包,您可以使用此代码片段列出所有后代进程:

pid=2235; python3 -c "import psutil
for c in psutil.Process($pid).children(True):
  print(c.pid)"
Run Code Online (Sandbox Code Playgroud)

(例如,psutil 软件包作为tracerFedora/CentOS 上可用的命令的依赖项安装。)

或者,您可以在 bourne shell 中对进程树进行广度优先遍历:

ps=2235; while [ "$ps" ]; do echo $ps; ps=$(echo $ps | xargs -n1 pgrep -P); \
  done | tail -n +2 | tr " " "\n"
Run Code Online (Sandbox Code Playgroud)

为了计算 pid 的传递闭包,可以省略尾部。

请注意,上面的代码没有使用递归,并且也在 ksh-88 中运行。

在 Linux 上,可以消除该pgrep调用,而是从以下位置读取信息/proc

ps=2235; while [ "$ps" ]; do echo $ps ; \
  ps=$(for p in $ps; do cat /proc/$p/task/$p/children; done); done \
  | tr " " "\n"' | tail -n +2
Run Code Online (Sandbox Code Playgroud)

这是更高效的,因为我们为每个 PID 保存一次 fork/exec,并pgrep在每次调用中执行一些额外的工作。