53 votes

ps : Comment obtenir récursivement tous les processus enfants pour un pid donné ?

Comment puis-je obtenir l'affichage de toute l'arborescence des processus générés par un processus donné sous forme d'arbre, et uniquement cet arbre, c'est-à-dire aucun autre processus ?

Le résultat pourrait par exemple ressembler à

 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

Je n'ai pas pu obtenir le résultat souhaité uniquement avec les paramètres de ps .

La méthode suivante donne le résultat souhaité mais semble un peu compliquée :

#!/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`

Quelqu'un a-t-il une solution plus simple ?

52voto

TrueY Points 650

Le pstree est une très bonne solution, mais elle est un peu réticente. J'utilise ps --forest au lieu de cela. Mais pas pour un PID ( -p ) parce qu'il n'imprime que le processus spécifique, mais pour la session ( -g ). Il peut imprimer n'importe quelle information ps peut être imprimée dans un arbre ASCII fantaisiste définissant les -o option.

Voici donc ma suggestion pour résoudre ce problème :

ps --forest -o pid,tty,stat,time,cmd -g 2795

Si le processus n'est pas un chef de session, il faut faire preuve d'un peu plus de doigté :

ps --forest -o pid,tty,stat,time,cmd -g $(ps -o sid= -p 2795)

Il récupère d'abord l'identifiant de session (SID) du processus en cours, puis appelle à nouveau ps avec cet identifiant.

Si les en-têtes de colonnes ne sont pas nécessaires, ajoutez un '=' après chaque définition de colonne dans les options '-o', comme par exemple :

ps --forest -o pid=,tty=,stat=,time=,cmd= -g $(ps -o sid= -p 2795)

Un exemple d'exécution et le résultat :

$ 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

Malheureusement, cela ne fonctionne pas pour screen car il définit le sid pour chaque écran enfant et pour tous les bash petits-enfants.

Pour obtenir tous les processus engendrés par un processus, l'arbre entier doit être construit. J'ai utilisé awk pour cela. Dans un premier temps, il construit un tableau de hachage contenant tous les PID => ,child,child... . À la fin, il appelle une fonction récursive pour extraire tous les processus enfants d'un processus donné. Le résultat est transmis à une autre fonction ps pour formater le résultat. Le PID réel doit être écrit en tant qu'argument de la commande awk au lieu de <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)}')

Pour un processus SCREEN (pid=8041), l'exemple de sortie ressemble à ceci :

  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

30voto

Eroen Points 6113
pstree ${pid}

${pid} est le pid du processus parent.

Sur Gentoo Linux, pstree se trouve dans le paquet "psmisc", apparemment situé à l'adresse http://psmisc.sourceforge.net/

16voto

xzfc Points 471

Voici ma version qui fonctionne instantanément (parce que ps exécuté une seule fois). Fonctionne avec bash et 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
)

4voto

kivetros Points 484

J'ai créé un petit script bash script pour créer une liste des pid des processus enfants d'un parent. Recursivement jusqu'à ce qu'il trouve le dernier processus enfant qui n'a pas d'enfant. Il ne donne pas de vue arborescente. Il se contente de lister tous les 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

le premier argument de list_offspring est le pid du parent

4voto

edi9999 Points 159

ps -H -g "$pid" -o comm

n'ajoute pas d'arbre en soi, il s'agit simplement de la liste des processus.

donne par exemple

COMMAND
bash
  nvim
    python

SistemesEz.com

SystemesEZ est une communauté de sysadmins où vous pouvez résoudre vos problèmes et vos doutes. Vous pouvez consulter les questions des autres sysadmins, poser vos propres questions ou résoudre celles des autres.

Powered by:

X