bashsynchronizationmultiprocessingprogress-barshared-variable

Multiprocess with shared variable in bash


I'm trying to achieve a dynamic progress bar in bash script, the kind we see when installing new packages. In order to do this, a randomtask would call a progressbar script as a background task and feed it with some integer values.

The first script uses a pipe to feed the second.

#!/bin/bash
# randomtask

pbar_x=0            # percentage of progress
pbar_xmax=100

while [[ $pbar_x != $pbar_xmax ]]; do
    echo "$pbar_x"
    sleep 1
done | ./progressbar &

# do things
(( pbar_x++ ))

# when task is done
(( pbar_x = pbar_xmax ))

Hence, the second script needs to constantly receive the integer, and print it.

#!/bin/bash
# progressbar

while [ 1 ]; do
    read x
    echo "progress: $x%"
done

But here, the second script doesn't receive the values as they are updated. What did I do wrong ?


Solution

  • I'm on WSL, which means I can't use mkfifo. And coproc seemed to perfectly answer my need, so I searched and eventually found this: coproc usage with exemples [bash-hackers wiki].

    We start the process with coproc and redirect its output to stdout:

    { coproc PBAR { ./progressbar; } >&3; } 3>&1
    

    Then we can access its in and out via file descriptors ${PBAR[0]}(output) and ${PBAR[1]}(input)

        echo "$pbar_x" >&"${PBAR[1]}"
    

    randomtask

    #!/bin/bash
    
    pbar_x=0            # percentage of progress
    pbar_xmax=100
    
    { coproc PBAR { ./progressbar; } >&3; } 3>&1
    
    while (( pbar_x <= 10)); do
        echo $(( pbar_x++ )) >&"${PBAR[1]}"
        sleep 1
    done
    
    # do things
    echo $(( pbar_x++ )) >&"${PBAR[1]}"
    
    # when task is done
    echo $(( pbar_x = pbar_xmax )) >&"${PBAR[1]}"
    

    progressbar

    #!/bin/bash
    
    while read x; do
        echo "progress: $x%"
    done
    

    Please note that :

    The coproc keyword is not specified by POSIX(R).

    The coproc keyword appeared in Bash version 4.0-alpha