Comment puis-je obtenir l’ensemble de l’arbre de processus généré par un processus donné affiché sous forme d’arbre et uniquement cet arbre c’est-à-dire aucun autre processus?
La sortie 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 ne pouvais pas obtenir le résultat souhaité uniquement avec des paramètres de ps
.
Ce qui suit donne le résultat souhaité mais semble un peu impliqué:
#!/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 at-il une solution plus facile?
La pstree
est une très bonne solution, mais elle est un peu réticente. J'utilise ps --forest
à la place. Mais pas pour une PID
(-p
) car elle imprime uniquement le processus spécifique, mais pour la session (-g
). Il peut imprimer toutes les informations que ps
peut imprimer dans une arborescence de fantaisie ASCII définissant l'option -o
.
Donc, ma suggestion pour ce problème:
ps --forest -o pid,tty,stat,time,cmd -g 2795
Si le processus n'est pas un chef de session, un truc un peu plus doit être appliqué:
ps --forest -o pid,tty,stat,time,cmd -g $(ps -o sid= -p 2795)
Cela récupère d'abord l'identifiant de session (SID) du processus en cours, puis appelle à nouveau ps avec ce sid.
Si les en-têtes de colonne ne sont pas nécessaires, ajoutez un '=' après chaque définition de colonne dans les options '-o', comme suit:
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 de chaque écran enfant et de tous les bash enfants.
Pour obtenir tous les processus engendrés par un processus, il faut construire l'arbre entier. J'ai utilisé awk pour cela. Au début, il construit un tableau de hachage contenant tout le 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 passé à une autre ps
pour formater le résultat. Le PID réel doit être écrit en tant qu'argument pour 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
pstree ${pid}
où $ {pid} est le pid du processus parent.
Sur gentoo, pstree est dans le paquet "psmisc", apparemment situé à http://psmisc.sourceforge.net/
Voici ma version qui s'exécute instantanément (car ps
n'a été exécuté qu'une fois). Fonctionne en 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
)
ps -H -g "$pid" -o comm
n’ajoute pas d’arbre en soi, c’est juste la liste des processus.
donne par exemple
COMMAND
bash
nvim
python
Je travaille pour trouver une solution au même problème. Fondamentalement, ps manpage ne documente aucune option permettant de faire ce que nous voulons avec une seule commande. Conclusion: un script est nécessaire.
Je suis venu avec un script très similaire au vôtre. Je l'ai collé dans mon ~/.bashrc pour que je puisse l'utiliser depuis n'importe quel shell.
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
}
J'ai créé un petit script bash pour créer une liste de pid des processus enfants d'un parent. Récursivement jusqu'à ce qu'il trouve le dernier processus enfant qui n'a aucun enfant. Cela ne vous donne pas une vue en arbre. Il ne liste que 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 parent
Cela ne donne que les pid + enfants pids chacun sur une ligne, ce qui est utile pour un traitement ultérieur.
pidtree() {
for _pid in "$@"; do
echo $_pid
pidtree `ps --ppid $_pid -o pid h`
done
}
En route sur la ligne de commande:
ps -o time,pid,ppid,cmd --forest -g -p $(pgrep -x bash)
il produit:
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
manière plus élégante de cette manière est de définir une fonction dans .bashrc
:
function subps()
{
process=$(pgrep -x $1)
ps -o time,pid,ppid,cmd --forest -g -p $process
}
puis sur la ligne de commande exécutée:
subps bash
J'ai fait un script similaire basé sur celui de Philippe
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"
}
Ceci affiche tous les pids enfants, petits-enfants, etc. au format délimité par des espaces. Cela peut, à son tour, être transmis à ps, comme dans
ps -p $ (pidlist pid )