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)
Сначала он получает идентификатор сеанса (SID) текущего процесса, а затем снова вызывает ps с этим sid.
Если заголовки столбцов не нужны, добавьте «=» после каждого определения столбца в параметрах «-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
как он устанавливает 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