ps: Як я можу рекурсивно отримати весь дочірній процес за певний під


43

Як я можу отримати все дерево процесу, породжене заданим процесом, відображеним як дерево, і лише це дерево, тобто ніяких інших процесів?

Вихід може наприклад виглядати

 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`

Хтось має простіше рішення?


Не відповідь, але почніть з ps auxf.
jftuga

3
@jtfuga Насправді з цього я почав, але це дає мені всі процеси, і саме це я не хочу.
кинан

Відповіді:


38

Це 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оскільки це встановлює сторону для екрану кожної дитини та всіх онуків.

Щоб усі процеси були породжені процесом, потрібно створити все дерево. Я використовував для цього. Спочатку він будує хеш-масив, щоб містити всіх 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)}')

Для 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

Проблема з цим (я знаю, це стара відповідь) - опція -forest працює лише в Linux (або інших командах "ps" на основі gnu). Solaris та MacOS це не люблять.
Арман

@TrueY Ви знаєте API C, який може це зробити? Дякую
Bionix1441,

Bionix Ні, вибачте ... Я можу читати / proc / <PID> каталоги для створення цього дерева.
TrueY

1
Схоже, це повинно бути простим, якби psбув варіант прапора фільтра просто для фільтрації всіх нащадків PID.
CMCDragonkai

27
pstree ${pid}

де ${pid}pid батьківського процесу.

На Gentoo Linux pstreeзнаходиться в пакеті "psmisc", який, мабуть, знаходиться за адресоюhttp://psmisc.sourceforge.net/


9
Дякую, мав би зазначити, що я переглянув pstree, але пропустив більш детальний формат виводу. Однак pstree -p <pid>принаймні надрукуйте придатки, які досить близько.
кинан

2
У мене є і ця проблема, мені потрібно збирати всі дитячі присипи рекурсивно, але мені потрібні лише пришпи, тому мені доведеться sedвсе це .. ммм це працює :)pstree -pn 4008 |grep -o "([[:digit:]]*)" |grep -o "[[:digit:]]*"
Водолій Сила

12

Ось моя версія, яка працює миттєво (бо 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
)

1
Це також виводить друк поточного процесу, який ви можете або не хочете. Я не хотів, щоб поточний процес перераховувався (лише нащадки поточного процесу), тому я змінив сценарій, перемістивши echo $1всередину першого для циклу та змінивши його на echo $i.
Марк Лаката

1
Я ось-ось збирався написати таку функцію, коли знайшов це. Це єдине рішення, яке, здається, працює на MacOS, Linux та Solaris. Чудова робота. Люблю, що ти покладаєшся на один запуск PS, щоб виконати роботу в пам'яті.
Арман

3

Я створив невеликий скрипт bash для створення списків підручників батьківських дочірніх процесів. Рекурсивно, поки вона не знайде останнього дочірнього процесу, у якого немає жодної дитини. Це не дає вам виду на дерево. Він просто перераховує всі піди.

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 - це батьківський під


1
Уже є кілька інших відповідей, які дають скрипт bash, який не друкує фактичне дерево, включаючи один у самому питанні. Які переваги має ваша (часткова) відповідь перед існуючими (частковими) відповідями?
Девід Річербі

Я використав рекурсію і додав пояснення. Думав, що це може комусь допомогти. Це робить саме те, що вимагає назва.
Мерейн

Мені подобається використання тут pgrep, оскільки ps може відрізнятися між варіантами unix.
Джон Сакмайстер


2

Я працюю над тим, щоб знайти вирішення саме такої проблеми. В основному, man manpage не містить жодної опції, що дозволяє виконувати те, що ми хочемо, за допомогою однієї команди. Висновок: потрібен сценарій.

Я придумав сценарій, дуже схожий на ваш. Я вставив його в ~ / .bashrc, щоб я міг використовувати його з будь-якої оболонки.

pidtree() {
  local parent=$1
  local list=
  while [ "$parent" ] ; do     
    if [ -n "$list" ] ; then
      list="$list,$parent"
    else
      list="$parent"
    fi
    parent=$(ps --ppid $parent -o pid h)
  done
  ps -f -p $list f
}

1

По дорозі в командному рядку:

ps -o time,pid,ppid,cmd --forest -g -p $(pgrep -x bash)

він виводить:

    TIME   PID  PPID CMD
00:00:00  5484  5480 bash
00:00:01  5531  5484  \_ emacs -nw .bashrc
00:00:01  2986  2984 /bin/bash
00:00:00  4731  2986  \_ redshift
00:00:00  5543  2986  \_ ps -o time,pid,ppid,cmd --forest -g -p 2986 5484

Більш елегантним способом є визначення функції в .bashrc:

function subps()                                                                                    
{                                                                                                   
    process=$(pgrep -x $1)                                                                                                                                                                     
    ps -o time,pid,ppid,cmd --forest -g -p $process                                                 
}    

потім у командному рядку запустіть:

subps bash

1

Це дає лише під + підручники для дітей у кожному рядку, що корисно для подальшої обробки.

pidtree() {
    for _pid in "$@"; do
        echo $_pid
        pidtree `ps --ppid $_pid -o pid h`
    done
}

0

Я зробив аналогічний сценарій на основі Філіппа

pidlist() {
local thispid=$1
local fulllist=
local childlist=
childlist=$(ps --ppid $thispid -o pid h)
for pid in $childlist
do
  fulllist="$(pidlist $pid) $fulllist"
done
echo "$thispid $fulllist"
}

Це виводить усі підди для дитини, онука тощо у форматі, обмеженому простором. Це, в свою чергу, може подаватися в ps, як в

ps -p $ (pidlist pid )


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.