优雅地获取后代进程列表

优雅地获取后代进程列表

我想获得从 . 继承的所有进程(例如子进程、孙进程等)的列表$pid。这是我想出的最简单的方法:

pstree -p $pid | tr "\n" " " |sed "s/[^0-9]/ /g" |sed "s/\s\s*/ /g"

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

答案1

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

pstree -p $pid | grep -o '([0-9]\+)' | grep -o '[0-9]\+'

或者使用 Perl:

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

我们正在寻找括号内的数字,这样当我们遇到 时,我们就不会将 2 作为子进程给出gif2png(3012)。但如果命令名称包含带括号的数字,则一切都将失败。文本处理所能帮助您的就这么多了。

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

pgrphack my_command args

或者你可以再次转向 Perl:

perl -e 'setpgid or die; exec { $ARGV[0] } @ARGV;' my_command args

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

答案2

descendent_pids() {
    pids=$(pgrep -P $1)
    echo $pids
    for pid in $pids; do
        descendent_pids $pid
    done
}

答案3

还有正确性的问题。天真地解析输出pstree由于以下几个原因存在问题:

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

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

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

(例如,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"

为了计算 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

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

答案4

我发现的最短版本也可以正确处理以下命令pop3d

pstree -p $pid | perl -ne 's/\((\d+)\)/print " $1"/ge'

如果您的命令具有奇怪的名称,例如:my(23)prog,它会错误地处理。

相关内容