1

Consider this code:

job()
{
  local id=$1
  sleep $id
}
do_job_in_parallel()
{
  local pids=()

  # run subshells
  for id in $(seq 4)
  do
    job $id &
    pids=("${pids[@]}" $!)
  done

  # wait subshells
  for ((i=0; i<${#pids[@]}; ++i))
  do
    local pid=${pids[$i]}
    wait $pid
    exit_status=$?
    if [[ $exit_status -ne 0 ]]
    then
      echo "job with pid $pid failed with exit status $exit_status"
      #TODO: kill all subshells
    fi
  done
}

Consider that we need to implement "if any subshell failed, then all subshells failed" logic. If waiting of X and Y is done sequentially (as in the code above) AND if, for example, Y failed while waiting of X, then there is no need to wait X. How to implement, more precisely, "if any subshell failed, then kill immediately all other subshells"?

1 Answer 1

2

I don't think there's an easy solution with a for loop and wait but you can use GNU parallel (https://www.gnu.org/software/parallel/) for this. It should be available for your distribution in your favorite package manager.

#!/bin/bash
#

do_job()
{
  local id=$1
  sleep $id
}


export -f do_job

do_job_in_parallel()
{
    parallel --halt now,done=1 do_job "{}" ::: $(seq 4)
}

do_job_in_parallel

Besides "now,done=1" you have other options: soon instead of now only stops starting new jobs but let ongoing processes exit normally, success=1 stops them only if the process exited with 0, fail=1 only if if exited with something else, you can specify a number or a percentage of jobs, etc. All the details are in the documentation: https://www.gnu.org/software/parallel/parallel.html.

8
  • Re: "I don't think there's an easy solution with a for loop and wait": indded, attempt to use wait_pid $pid & leads to t5.sh: line 125: wait: pid 10921 is not a child of this shell.
    – pmor
    Nov 23, 2022 at 16:32
  • GNU parallel 20161222 says: parallel: Error: --halt now must be followed by ,success or ,fail..
    – pmor
    Nov 23, 2022 at 16:37
  • Do I need to export all nested functions and variables? Otherwise, it says environment: foo: command not found. Does set -o allexport need to be used?
    – pmor
    Nov 23, 2022 at 17:03
  • @pmor If it's simpler maybe you can put the job in a separate shell script? That way, it's a separate command altogether and you don't need to export functions.
    – lgeorget
    Nov 23, 2022 at 21:48
  • @pmor Another solution is "set -o allexport" (or "set -a" which does the same). Remember to do it before the functions and variables you wish to export.
    – lgeorget
    Nov 23, 2022 at 21:50

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .