Matching output from functions running in parallel in Bash

Viewed 204

My Bash script looks roughly like this:

#!/bin/bash
function a { echo -n "A is running..."; sleep 5; echo "done (A)" }
function b { echo -n "B is running..."; sleep 1; echo "done (B)" }
function c { echo -n "C is running..."; sleep 3; echo "done (C)" }

a
b
c

Because all three operations are not the fastest in the universe I was thinking about speeding things up by running things in parallel, like so:

a & b & c & wait

However, that messes up the output to something like this:

[1] 21405
A is running...[2] 21406
B is running...[3] 21408
C is running...done (B)
[2]  - 21406 done       b
done (A)
[1]  - 21405 done       a
done (C)
[3]  + 21408 done       c

Ideally, I'd like the output to be similar to that of the original job with the processes in a fixed order so the user can see what's currently running:

A is running...done (A)
B is running...done (B)
C is running...done (C)

This means that when B finishes I'd like something like this:

A is running...
B is running...done (B)
C is running...

Is that possible? What's a good way to achieve that without rewriting too much of the functions (preferably)?

And on a related note, is it possible to add a circuit breaker, i.e. if, say, B fails, A and C are automatically terminated?

1 Answers
#!/bin/bash                                                                     
function a { sleep 8; }                                                         
function b { sleep 10; }                                                        
function c { sleep 5; }                                                         

a &                                                                             
b &                                                                             
c &                                                                             

echo 'a is running.'                                                            
echo 'b is running.'                                                            
echo 'c is running.'                                                            

while true; do                                                                  
        wait -n                                                                 

        A=`jobs -l | cut -b2`                                                   


        echo -n -e "\e[3A"                                                      
        if [[ $A =~ 1 ]]; then                                                  
                echo 'a is running.'                                            
        else                                                                    
                echo 'a is running... (done).'                                  
        fi                                                                      
        if [[ $A =~ 2 ]]; then                                                  
                echo 'b is running.'                                            
        else                                                                    
                echo 'b is running... (done).'                                  
        fi                                                                      
        if [[ $A =~ 3 ]]; then                                                  
                echo 'c is running.'                                            
        else                                                                    
                echo 'c is running... (done).'                                  
        fi                                                                      

        if [ -z "$A" ]; then break; fi                                          
done

Note that command echo -n -e "\e[3A" move cursor 3 lines up.

Related