user239558
user239558

Reputation: 7306

set -e with multiple subshells. non-blocking wait -n

In a CI setting, I'd like to run multiple jobs in the background, and use set -e to exit on the first error.

This requires using wait -n instead of wait, but for increasing throughput I'd then want to move the for i in {1..20}; do wait -n; done to the end of the script.

Unfortunately, this means that it is hard to track the errors.

Rather, what I would want is to do the equivalent to a non-blocking wait -n often, and exit as soon as possible.

Is this possible or do I have to write my bash scripts as a Makefile?

Upvotes: 0

Views: 332

Answers (1)

Socowi
Socowi

Reputation: 27370

Alternative Approach: Emulate set -e for background jobs

Instead of checking the jobs all the time it could be easier and more efficient to exit the script directly when a job fails. To this end, append ... || kill $$ to every job you start:

# before
myCommand &
myProgram arg1 arg2 &

# after
myCommand || kill $$ &
myProgram arg1 arg2 || kill $$ &

Non-Blocking wait -n

If you really have to, you can write your own non-blocking wait -n with a little trick:

nextJobExitCode() {
    sleep 0.1 &
    wait -n
    exitCode="$?"
    kill %%
    return "$exitCode"
}

The function nextJobExitCode waits at most 0.1 seconds for your jobs. If none of your jobs were already finished or did finish in that 0.1 seconds, nextJobExitCode will terminate with exit code 0.

Example usage

set -e

sleep 1 &            # job 1
(sleep 3; false) &   # job 2

nextJobExitCode      # won't exit. No jobs finished yet
sleep 2
nextJobExitCode      # won't exit. Job 1 finished with 0
sleep 2
nextJobExitCode      # will exit! Job 2 finished with 1

Upvotes: 3

Related Questions