如何才能让给定进程生成的整个进程树显示为一棵树,并且只显示那棵树,即没有其他进程?
输出可能看起来像
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
我无法仅通过参数来获得期望的结果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`
有人有更简单的解决方案吗?
答案1
是pstree
一个很好的解决方案,但它有点保守。我改用ps --forest
。但不适用于PID
(-p
),因为它只打印特定进程,而是适用于会话(-g
)。它可以打印出任何信息,ps
可以打印在定义选项的花哨的 ASCII 艺术树中-o
。
所以我对这个问题的建议是:
ps --forest -o pid,tty,stat,time,cmd -g 2795
如果该进程不是会话领导者,则需要应用一些技巧:
ps --forest -o pid,tty,stat,time,cmd -g $(ps -o sid= -p 2795)
这首先获取当前进程的会话 ID (SID),然后使用该 sid 再次调用 ps。
如果不需要列标题,则在“-o”选项中每个列定义后添加“=”,例如:
ps --forest -o pid=,tty=,stat=,time=,cmd= -g $(ps -o sid= -p 2795)
示例运行及其结果:
$ 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
不幸的是,这不起作用,screen
因为它为每个子屏幕和所有孙子 bash 设置了 sid。
要获取某个进程生成的所有进程,需要构建整棵树。我使用了awk为此。首先,它构建一个哈希数组来包含所有PID => ,child,child...
。最后,它调用递归函数来提取给定进程的所有子进程。结果被传递给另一个函数ps
来格式化结果。实际的 PID 必须作为参数写入awk代替<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)}')
对于 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
答案2
pstree ${pid}
${pid}
其中父进程的 pid 是。
在 Gentoo Linux 上,pstree
位于“psmisc”包中,位置为http://psmisc.sourceforge.net/
答案3
这是我的版本,可以立即运行(因为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
)
答案4
我创建了一个小型 bash 脚本来创建父进程的子进程的 pid 列表。递归执行,直到找到最后一个没有任何子进程的子进程。它不会提供树状视图。它只列出所有 pid。
function list_offspring {
tp=`pgrep -P $1` #get childs pids of parent pid
for i in $tp; do #loop through childs
if [ -z $i ]; then #check if empty list
exit #if empty: exit
else #else
echo -n "$i " #print childs pid
list_offspring $i #call list_offspring again with child pid as the parent
fi;
done
}
list_offspring $1
list_offspring 的第一个参数是父进程的 pid