Codelearnerr
Codelearnerr

Reputation: 31

Script which takes a PID as operand and prints PIDs of all its children, grandchildren, etc

I am new at programming. As I know is every process can create a child process. When you open a terminal, a process is created, and when you call a command inside the terminal a child process is created. I want to see that child processes and understand how it works. My friend shared his code with me but It is too complicated for me. I want to make it more simple. I hope someone can help me. Have a nice day to everyone! Here is the code:

    #!/bin/bash

#Function that will display the process with the parent process ID given as argument
function get_child()
{
        #depth will hold the number of generation. E.g 0 for main process, 1 for children, 2 for grandchildre and so on

local depth=$depth
        # ps --ppid $parent will get the processes whose parent ID is $parent

output=`ps --ppid $parent`
        #increment the depth

depth=$(($depth+1))
        # Pipe the value of $output to tail -n + 2. It will remove the first line from $output because that line only contains title of the columns
        # awk '{print $1}' will only print the first column (Process ID) of eachline
        # While read child will iterate over all the process IDs referred as $child

echo "$output" | tail -n +2 | awk '{print $1}' | while read child

do
                #If $child is not empty i.e. it contains a process ID then echo the child process id and send that process id as parent process id to the get_child() function recursively

if [ $child ]
                then
                        for((i=0;i<depth;i++))
                        do
                                echo -n "-"
                        done
                        echo $depth. $child
                        parent=$child
                        get_child $child $depth
                fi
        done
}

parent=$1
depth=0
echo $parent
get_child $parent $depth

Upvotes: 3

Views: 258

Answers (2)

oguz ismail
oguz ismail

Reputation: 50750

Invoking ps multiple times would yield inaccurate results as new processes may be created and the old ones may terminate between invocations.

Taking a single snapshot and drawing the process tree based on that sure is a better approach; it would produce an accurate result at least for an instant.

The function below does that. Awk is for portability (not all ps implementations have --ppid).

ptree() {
  ps -A -o pid= -o ppid= |
    awk -v pid="${1:-1}" '
    function ptree(ppid, arm, i) {
      print arm ppid
      sub(/ ?$/, "- ", arm)
      for (i=1; i<=count[ppid]; ++i)
        ptree(pids[ppid,i], arm)
    }
    {
      pids[$2,++count[$2]] = $1
      ppids[$2]
    }
    END {
      if (pid in ppids)
        ptree(pid)
    }'
}

Upvotes: 1

L&#233;a Gris
L&#233;a Gris

Reputation: 19555

A short version of your algorithm.

I intentionally leave it without comment, so you can do the research on the Bash features and syntax, and gain some knowledge on your own for your assignment.

#!/usr/bin/env bash

get_child()
{
  local -i pid=0 ppid=$1 depth=$2
  printf '%*s%d. %d\n' "$depth" '' "$depth" "$ppid"
  while read -r pid; do
    ((pid)) && get_child $pid $((depth + 1))
  done < <(ps -o pid= --ppid $ppid)
}

get_child $1 0

No Bashism version:

#!/usr/bin/env sh

get_child()
{
  p=0
  printf '%*s%d. %d\n' $2 '' $2 $1
  ps -o pid= --ppid $1 |
    while read -r p; do
      [ $p -ne 0 ] && get_child $p $(($2 + 1))
    done
}

get_child $1 0

Upvotes: 3

Related Questions