Linux – How to create a process tree

commandcommand linelinuxprocess

I have some code that kills processes and their children/grandchildren. I want to test this code.

Currently I'm doing $ watch date > date.txt, which creates a process with a child.

Is there any way to create a parent -> child -> grandchild tree? What command can make that happen?

Best Answer

#!/bin/sh
#This is a process with an id of $$

( sleep 1000 )&               #this creates an idle child
( (sleep 1000)& sleep 1000 )& #this creates an idle child and grandchild
wait                          #this waits for direct children to finish

Running the above as ./1.sh & on my system created the following process tree:

$ command ps -o pid,ppid,pgrp,stat,args,wchan --forest
  PID  PPID  PGRP STAT COMMAND                     WCHAN
24949  4783 24949 Ss   /bin/bash                   wait
25153 24949 25153 S     \_ /bin/sh ./1.sh          sigsuspend
25155 25153 25153 S     |   \_ sleep 1000          hrtimer_nanosleep
25156 25153 25153 S     |   \_ sleep 1000          hrtimer_nanosleep
25158 25156 25153 S     |       \_ sleep 1000      hrtimer_nanosleep

You can notice that the tree has the same process group (PGRP) of 25153, which is identical to the PID of the first process. The shell creates a process group whenever you start a new command in interactive mode (or with job control explicitly turned on).

The PGRP mechanism allows the shell to send a signal to the whole process group at once without creating a race condition. This is used for job control, and when your script runs and a foreground job, for sending:

  • (SIG)INTR when the user presses C-C
  • (SIG)QUIT when the user presses C-\
  • (SIG)STP when the user presses C-Z

You can do the same by doing, for example:

kill -INTR -25153 

where INTR is the signal and 25153 is the process group you want to send the signal to. The - before the 25153 means you're targeting a PGRP id rather than a PID.

In your case, the signal you should be sending is -TERM (request termination). Term is the default signal kill sends, however, you have to specify it explicitly if you're targeting a group rather than a PID.

kill -TERM -25153

If you want to kill the process group of the last background job you started, you can do:

kill -TERM -$!
Related Question