Modify global variable from subshell loop in bash

204 views Asked by At

My objective is to measure the current system load as a percentage, and then blink an LED for that percentage of a second. To do this I had a function "get_load" which measures the average load over a second, in a while loop, and was running this as a subshell like get_load &. The get_load function is also defining a global LASTLOAD variable after each iteration. After that I have a flip_led function which turns the led on, sleeps for 1-LASTLOAD seconds, turns it off and then sleeps for 1-LASTLOAD seconds (should total to one)

The problem is, the global LASTLOAD variable never seems to be updated, or at least doesnt propagate into the flip_led loop.

My question is how can I run a loop in a subshell, but have that subshell influence global variables in the initial script?

Heres the script itself

readonly LEDTRIGGER="/sys/class/leds/led0/trigger"
readonly LEDBRIGHTNESS="/sys/class/leds/led0/brightness"

LASTLOAD=0
ISRUNNING=1

function get_load() {
    # Define all local variables used in function
    local user1 sys1 idle1 user2 sys2 idle2 u s i load

    while [[ $ISRUNNING -eq 1 ]]; do
        # Get initial usage
        read -r user1 sys1 idle1 \
            <<<"$(grep 'cpu ' /proc/stat | awk '{print $2" "$4" "$5}')"
        sleep 1
        # Get usage after a second has passed
        read -r user2 sys2 idle2 \
            <<<"$(grep 'cpu ' /proc/stat | awk '{print $2" "$4" "$5}')"

        u=$(echo "scale=4;$user2-$user1" | bc)
        s=$(echo "scale=4;$sys2-$sys1" | bc)
        i=$(echo "scale=4;$idle2-$idle1" | bc)

        # Return the average usage over the last second rounded
        load=$(echo "scale=4;($u+$s)*100/($u+$s+$i)" | $BC)
        # loadint=$(echo "($load+0.5)/1" | $BC)
        percent=$(echo "scale=4;$load/100" | $BC)

        # echo "load: $load, loadint: $loadint, percentage: $percent"
        # return "$loadint"
        # echo "$percent"
        LASTLOAD=$percent
        echo "$LASTLOAD"
    done
}

function flip_led() {
    while [[ $ISRUNNING -eq 1 ]]; do
        local remainder
        remainder=$(echo "scale=2;1-$LASTLOAD" | $BC)
        echo 1 | sudo tee $LEDBRIGHTNESS >/dev/null
        echo "led on for $LASTLOAD, off for $remainder"
        $SLEEP "$LASTLOAD"
        echo 0 | sudo tee $LEDBRIGHTNESS >/dev/null
        $SLEEP "$remainder"
    done
}

echo none | sudo tee $LEDTRIGGER >/dev/null
echo 0 | sudo tee $LEDBRIGHTNESS >/dev/null

get_load &
flip_led &

0

There are 0 answers