3

I would like to report the grand child process id to the parent either by storing it in a variable and exporting it or some other means. How is it possible? Below a small example.

example .

parent.sh
    ./child.sh &
     wait
     sleep 10
     echo $grandchild_pid

child.sh
    ./grandchild.sh &
     export grandchild_pid=$!
infoclogged
  • 3,641
  • 5
  • 32
  • 53

3 Answers3

4

One approach is to use a FIFO:

tempdir=$(mktemp -t -d fifodir.XXXXXX) # tempdir for our named pipe
trap 'rm -rf "$tempdir"' EXIT          # ...arrange for it to be deleted on exit

mkfifo "$tempdir/child"                # create our temporary FIFO
./child.sh 3>"$tempdir/child" &        # start our background process, FD 3 to the FIFO

sleep 10                               # do whatever
read grandchild_pid <"$tempdir/child"  # read from the FIFO

echo "Our grandchild's PID is $grandchild_pid"

...and, in child.sh:

./grandchild.sh 3>&- &  # start the grandchild in the background
(echo "$!" >&3 &)       # write PID to FD3 in background so we don't block on the parent
exec 3>&-               # close the FD from the child, so only the backgrounded echo has it
Charles Duffy
  • 280,126
  • 43
  • 390
  • 441
  • How about using an in-memory FIFO, like on `/dev/shm` (to avoid going to disk)? – randomir Oct 26 '17 at 15:43
  • @randomir, hardly matters -- the *data* isn't going to disk, after all, just the handle used to connect the processes. But I should have used `mktemp -t`, so that `TEMPDIR` is honored. – Charles Duffy Oct 26 '17 at 15:45
  • That's true. Probably not worth the effort, especially if this is a one-time thing.. – randomir Oct 26 '17 at 15:47
  • AFAIK, you don't even need template: `mktemp -td` should do. – randomir Oct 26 '17 at 15:48
  • can you please tell the difference between storing and reading from a file and this method? advantages / disadvantages against a proper disk file like /tmp/child.pid. – infoclogged Oct 27 '17 at 07:42
  • @infoclogged, a FIFO provides synchronization: The reader will block until there's a writer, the writer will block until there's a reader (this is why we put the write in the background). With a regular file, you don't have any guaranteed safe way to wait until there's actually data in it ready to read, unless you build it yourself w/ primitives such as `flock`. With a named pipe, there's no such thing as "data in it" at all -- it just sets up a connection between the process that opens it for read and the process that opens it for write. – Charles Duffy Oct 27 '17 at 11:31
  • @infoclogged, ...and as an aside: using fixed filenames in `/tmp` is actually a security risk, since someone else who knows the names your script can use can put symlinks there first, causing your script to overwrite files you have write access to but they don't. Using `mktemp` mitigates this, as it generates random names, and (when creating a directory) uses much more restrictive permissions than `/tmp` itself has. – Charles Duffy Oct 27 '17 at 11:33
1

You can find all the "grandchildren" of a process like so:

declare -a child_pids
declare -a grandchild_pids
child_pids=( $( ps -h -o pid --ppid $$ ) )
for pid in ${child_pids[*]}; do
   grandchild_pids+=( $( ps -h -o pid --ppid $pid ) )
done
Jack
  • 5,801
  • 1
  • 15
  • 20
  • 1
    *grumbles about spreading the `array=( $(command-substitution) )` string-splitting idiom*. Sure, your only values are numeric here (and so won't cause problems with `IFS` having a default value), but the next person who follows this code as an example might use it in a place where that's not true. Same for `${child_pids[*]}`. – Charles Duffy Oct 26 '17 at 15:31
1

One solution, but not the best, is print the pids of your childs and grandchilds on a file. Then the parent can cat this file and get the data.

A little example:

Parent Process:

#!/bin/bash

echo "Im the parent"
rm .pids.childs

./child.sh &
wait


echo "my son is: $(cat .pids.childs | grep SON)"
echo "my gchild is: $(cat .pids.childs | grep GCH)"
echo "Parent Finish"
exit 0

Child Process:

#!/bin/bash

echo "Im the child"
echo "SON_PID=$$" >> .pids.childs

./gchild.sh &
wait

echo "Child Finish"
exit 0

GrandChild Process: #!/bin/bash

echo "Im the gchild"

echo "GCH_PID=$$" >> .pids.childs

echo "gchild Finish"
exit 0

It is not a great solution but it works

A.Villegas
  • 462
  • 7
  • 18
  • thank you for your time and answer. this was already my first approach, and still is and it works. however, I wanted some more elegant methods.. – infoclogged Oct 27 '17 at 07:35