13

I have the following scenario.

The user would type the PID of a process, and the script should show the process and it's subprocesses, sub-subprocesses (and so on) of PID, and it should list it in a tree format.

I tried using pstree PID and ps faux PID, but it doesn't work. It seems like it doesn't take PID of processes as arguments.

Any ideas please?

nbro
  • 15,395
  • 32
  • 113
  • 196
mkab
  • 221
  • 1
  • 2
  • 5

3 Answers3

26

Just wanted to document my steps related to this problem.

Say I execute this in a terminal:

~$ echo "read -p 'Press Enter'" > mytest.sh
~$ chmod +x mytest.sh
~$ bash -c bash
~$ bash -c ./mytest.sh

... and leave it waiting at the read input prompt. Then, I can always find the pid of mytest.sh like:

$ ps axf | grep mytest
20473 pts/2    S+     0:00              |   |   \_ grep --color=tty mytest
20308 pts/5    S+     0:00              |   |       \_ bash -c ./mytest.sh

... however, I'd like to output a ps axf tree limited to some parent of mytest.sh; looking at a full ps axf, we can see a hierarchy:

$ ps axf

 1489 ?        Sl     1:39              \_ gnome-terminal --sm-client-id 106ab86
 1511 ?        S      0:00              |   \_ gnome-pty-helper
...
20238 pts/5    Ss     0:00              |   \_ bash
20274 pts/5    S      0:00              |   |   \_ bash
20308 pts/5    S+     0:00              |   |       \_ bash -c ./mytest.sh
...

Then, say I don't want to 'scan' the gnome-terminal (1489) as parent, but instead I want to start at bash (20238).. So, I'd like to obtain this output:

$ ps f -p 20238 20274 20308
  PID TTY      STAT   TIME COMMAND
20238 pts/5    Ss     0:00 bash
20274 pts/5    S      0:00  \_ bash
20308 pts/5    S+     0:00      \_ bash -c ./mytest.sh

... except, I don't want to copy/paste the child PIDs manually :)

I could use pstree:

$ pstree -a -p 20238
bash,20238
  └─bash,20274
      └─bash,20308 -c ./mytest.sh

$ pstree -p 20238
bash(20238)───bash(20274)───bash(20308)

... unfortunately, the output is not exactly the same as in ps axf, which I prefer.

So, I can use pstree simply to obtain child PIDs:

$ pstree -p 20238 | sed 's/(/\n(/g' | grep '(' | sed 's/(\(.*\)).*/\1/'
20238
20274
20308

$ pstree -p 20238 | sed 's/(/\n(/g' | grep '(' | sed 's/(\(.*\)).*/\1/' | tr "\n" ,
20238,20274,20308,

and then use those to obtain a ps axf tree, based only on the PID of the parent:

$ ps f -p $(pstree -p 20238 | sed 's/(/\n(/g' | grep '(' | sed 's/(\(.*\)).*/\1/' | tr "\n" " ")
  PID TTY      STAT   TIME COMMAND
20238 pts/5    Ss     0:00 bash
20274 pts/5    S      0:00  \_ bash
20308 pts/5    S+     0:00      \_ bash -c ./mytest.sh

Well, hope this helps someone,
Cheers!

sdaau
  • 36,975
  • 46
  • 198
  • 278
  • 1
    Thanks you for the idea. My version (simpler in my opinion, with less pipes) : `pstree -lp 20238 | grep -Po '(?<=\()[0-9]+(?=\))' | xargs ps f -p` using only `grep` to get the PIDs (numbers preceeded and followed by parenthesis). I added the `-l` option to `pstree` because it cuts long lines by default (which hid some process for me). – syme Jan 29 '15 at 16:19
2

This is the bash script using only ps and awk. You can use at as a base for generating process tree.

ppid=$1
while true
do 
    forloop=FALSE
    # get all children by pid 
    for i in `ps -ef | awk '$3 == '$ppid' {print $2}'`
    do 
       # Here you have one of of the elements of tree 
       #   parent -> child
       echo $ppid - $i 
       forloop=TRUE
    done
    ppid=$i

    if [ "$forloop" = "FALSE" ]; then
       exit
    fi
 done
pmod
  • 10,450
  • 1
  • 37
  • 50
  • 1
    This script is very broken. For instance, the test should be `if [ "$FORLOOP" = "FALSE" ]`, with the whitespace exactly as given; as it is, that line tries to run a command called `[FORLOOP`. – Charles Duffy Mar 07 '11 at 02:00
  • 1
    ...also, having all-caps non-environment variable names is contrary to convention (risking namespace collision with both environment and built-in variables) – Charles Duffy Mar 07 '11 at 02:01
  • @Charles Duffy Thank you, good points (made it without shell). – pmod Mar 07 '11 at 18:09
1

Your first step is to pipe ps through awk and grep. By using awk, you can isolate either the 'this process PID' field or the 'parent process PID' field.

Or, have a stroll through the /proc file system.

bmargulies
  • 97,814
  • 39
  • 186
  • 310
  • I shouldn't use awk (according to my teacher). So I pipe on ps and used grep but it doesn't work. I used "ps -A| grep PID – mkab Mar 06 '11 at 22:57
  • @Jim: Yeah pstree PID works. I really should develop the habit of reading man pages. Thanks. – mkab Mar 06 '11 at 23:06
  • 4
    Oh, homework. I thought you wanted to solve a real problem. You'd need to use a more complex grep pattern that specifies the existence of the number that you do not want to match. – bmargulies Mar 06 '11 at 23:23