Super User is a question and answer site for computer enthusiasts and power users. It's 100% free, no registration required.

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

Context:

Users provide me their custom scripts to run. These scripts can be of any sort like scripts to start multiple GUI programs, backend services. I have no control over how the scripts are written. These scripts can be of blocking type i.e. execution waits till all the child processes (programs that are run sequentially) exit

#exaple of blocking script
echo "START"
first_program 
second_program 
echo "DONE"

or non blocking type i.e. ones that fork child process in the background and exit something like

#example of non-blocking script
echo "START"
first_program &
second_program &
echo "DONE"

What am I trying to achieve?

User provided scripts can be of any of the above two types or mix of both. My job is to run the script and wait till all the processes started by it exit and then shutdown the node. If its of blocking type, case is plain simple i.e. get the PID of script execution process and wait till ps -ef|grep -ef PID has no more entries. Non-blocking scripts are the ones giving me trouble

Is there a way I can get list of PIDs of all the child process spawned by execution of a script? Any pointers or hints will be highly appreciated

share|improve this question
    
I don;t think it is possible after the parent script has ended unless you can capture the parent's PID. If you are launching the scripts, you could wrap them in something like pid$(foo.sh; echo $!) which will give you the PID of foo.sh so you can then use ps --ppid. Will that work? – terdon Sep 6 '13 at 18:27
2  
Do the scripts have to run under the UID of the author user? If not, can you create a dummy user just for this purpose? You wouldn’t even need grep, just ps –udummy_user. Also, look at process groups. – Scott Sep 7 '13 at 2:08
    
This is more a type of workaround than a solution for your initial question: Open a new bash session. You can list all processes spawned from this shell using ps without any arguments (should be only bash and ps in the beginning). Start your script there. After it finished, wait until ps | wc -l reaches your expected value. – Tim Sep 8 '13 at 13:17
up vote 1 down vote accepted

Thanks guys for your responses.. I got the solution on stackoverflow

You can use wait to wait for all the background processes started by userscript to complete. Since wait only works on children of the current shell, you'll need to source their script instead of running it as a separate process.

( source userscript; wait )

Sourcing the script in an explicit subshell should simulate starting a new process closely enough. If not, you can also background the subshell, which forces a new process to be started, then wait for it to complete.

( source userscript; wait ) & wait

Here is the link for original answer by @chepner : http://stackoverflow.com/questions/18663196/how-to-get-list-of-all-child-process-spawned-by-a-script/18663969?noredirect=1#18663969

share|improve this answer
2  
I thought about this as well, but this solution fails when userscript starts a subscript in background which then starts another script in background. Your wait command will then wait for the children of userscript but not for its grandchildren. – Tim Sep 10 '13 at 7:56
    
@Tim Just realized that :( – irraju Sep 10 '13 at 14:03

To answer your question directly, the command

jobs -p

gives you the list of all child processes.

Alternative #1

But in your case it might be easier to just use the command wait without any params:

first_program &
second_program &
wait

This will wait until ALL child processes have finished.

Alternative #2

Another alternative is using $! to get the PID of the last program and perhaps accumulate in a variable, like so:

pids=""
first_program &
pids="$pids $!"
second_program &
pids="$pids $!"

and then use wait with that (this is in case you only want to wait for a subset of you child processes):

wait $pids

Alternative #3

OR, if you want to wait only until ANY process has finished, you can use

wait -n $pids

Bonus info

If you want a sigterm to your bash script to close your child processes as well, you will need to propagate the signal with something like this (put this somewhere at the top, before starting any process):

trap 'kill $(jobs -p)' SIGINT SIGTERM EXIT
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.