3

I have 2 functions:

One for the main job that takes some inconsistent time:

functionA {
        sleep 10  #FOR INSTANCE
    ((a++))  #added to try catching job finish
}

And other for drawing a progress:

functionB {
    # DOT PROGRESS COUNTER
}

I need functionB to be running ONLY while functionA is active, so i do:

a=0    
    until ((a>0))
        do
            functionA & functionB 
        done
    echo "functionA is done"

However, in result I get the endless loop of both functions.

Tried while loop as well - result is the same.

What should be done to stop functionB when functionA is done?

EDIT: in debugger i see that "$a" for functionB is always 0. Why?

faceless
  • 450
  • 4
  • 15

2 Answers2

1

If I am understanding your question correctly, I think this may do it—

#!/bin/bash
done=

functionA() {
    sleep 3         # Placeholder for the actual work functionA does
    done=y          # Tell the outer loop we're done
    kill "$1"       # Stop the progress indicator
}

functionB() {
    while :; do     # The progress indicator - run forever
        echo .
        sleep 1
    done
}

until [[ "$done" ]]; do
    functionB &
    functionA $!
done

$! is the PID of the last-spawned background process, in this case a bash subshell (a separate process) running functionB in the background.

I think functionB was always seeing $a as 0 because functionA was run in a subshell, so its changes to a never made it back to the main shell where functionB was running.

By contrast, the code above runs functionB in the subshell and lets functionA expressly kill that subshell from the main shell. That way functionA's changes to done are visible in the until loop (I think).

Example output:

$ ./test.sh
.
.
.
$

Another option

If functionA may have to run more than once, you can use this:

#!/bin/bash
done=

functionA() {
    sleep 3         # Do work
    done=y          # If functionA needs to run again, don't set $done
}

functionB() {
    while :; do     # Run forever, until terminated
        echo .
        sleep 1
    done
}

functionB &         # Start the progress indicator
progress_pid="$!"

until [[ "$done" ]]; do     # Do the work
    functionA
done

kill "$progress_pid"    # Stop the progress indicator
cxw
  • 16,685
  • 2
  • 45
  • 81
  • is there any way to rebuild this approach the way functionB would run few times while functionA is still running? (Because in my case functionA runs some unpredictably different time, so my progress runs 60 dots long : 1 per second, probing if A is still running, and then starts over from a new line). – faceless Aug 23 '18 at 13:26
  • @faceless Would you please ask that as a separate question, with the code you're currently using? I'm not sure I understand, and a question provides much more space for explanation than a comment does. Also, a new question will be more visible, and someone other than myself might have an answer for you. Thanks! Feel free to comment here with the link to the new question if you would like. – cxw Aug 23 '18 at 14:39
-2

I am not sure if I get you right, but this piece of code works for me:

#!/bin/sh
functionA () {
    sleep 10   #FOR INSTANCE
    ((a++))   #added to try catching job finish
}

functionB () {
    # DOT PROGRESS COUNTER
    echo -n "."
}

a=0
until ((a>10)) ; do
    functionA && functionB
done

echo "functionA is done"

Note that in bash a simple ampersand does not mean 'and': use && instead (see man bash).

In my system, I had to make another minor change from your example: the parentheses in every function declaration. Also I noticed that a is accesible from functionB without problems.

Gumboots
  • 27
  • 4
  • 1
    The single `&` was intentional; the OP wants `A` and `B` to run *simultaneously*, with `B` exiting once `A` finishes. Your code runs `A`, *then* runs `B`. – chepner Aug 21 '18 at 13:32