Home > OS >  In an loop, how do I execute a statement once when it is true, and then execute it again once when i
In an loop, how do I execute a statement once when it is true, and then execute it again once when i

Time:05-31

I've been trying to make a script for battery notifications for 15%, 10% and 5%. When the battery reaches those levels, it displays a notification saying to change my laptop. I made a variable called runOnce to state whether or not the script has already executed the if-statements once. If runOnce is false, run the if-statements inside a while-loop and if one of them is true, execute the commands and then set runOnce to true, stopping the while-loop. However, since I need the whole code to loop, so it also resets runOnce back to false. So, if the battery level is still the same, it repeatedly executes those commands. I've tried different solutions, but I can't figure out how not to let the script reset the variable back to false.

while true; do
    battery=$(cat /sys/class/power_supply/BAT0/capacity)
    batteryStatus=$(cat /sys/class/power_supply/BAT0/status)
    runOnce=false

    if [ $batteryStatus != "Charging" ]; then
        while [ "$runOnce" = false ]; do
                runOnce=false
                if [ $battery -eq 15 ]; then
                        notify-send --urgency=critical "Low Battery! (15%)" "Charge your laptop quickly."
                        espeak "Low battery. Please charge."
                        runOnce=true
                elif [ $battery -eq 10 ]; then
                        notify-send --urgency=critical "Critical Battery! (10%)" "Charge your laptop now. Before you lose your data. Seriously."
                        espeak "Critical battery. Please charge."
                        runOnce=true
                elif [ $battery -eq 5 ]; then
                        notify-send --urgency=critical "REALLY Critical Battery! (5%)" "Dude, your battery is going to go to the landfill soon."
                        espeak "Critical battery. Charge immediately."
                        runOnce=true
                fi
        done
    fi

    sleep 5
done

CodePudding user response:

You have to "remember state". You have to "remember" what battery was in what state between runs kind-of "above" the loop. Display message only when state changes - when changes from normal voltage to low, or changes from low to critical. Let's do some refactoring:

display_low() {
   notify-send --urgency=critical "Low Battery! (15%)" "Charge your laptop quickly."
    espeak "Low battery. Please charge."
}
display_crit() {
    notify-send --urgency=critical "Critical Battery! (10%)" "Charge your laptop now. Before you lose your data. Seriously."
    espeak "Critical battery. Please charge."
}
display_really_crit() {
    notify-send --urgency=critical "REALLY Critical Battery! (5%)" "Dude, your battery is going to go to the landfill soon."
    espeak "Critical battery. Charge immediately."
}

battery_to_state() {
   battery=$1
   # lets use bash syntax
   if (( battery <= 5 )); then
       echo really_crit
   elif (( battery <= 10 )); then
       echo crit
   elif (( battery <= 15 )); then
       echo low
   fi
   # if greater than 15, state is empty
}

laststate=
while true; do
    batteryStatus=$(cat /sys/class/power_supply/BAT0/status)
    battery=$(cat /sys/class/power_supply/BAT0/capacity)
    curstate=$(battery_to_state "$battery")
    if
       # Only display when not charging
       [[ "$batteryStatus" != "Charging" ]] &&
       # Only display if the state is not empty (below 15!)
       [[ -n "$curstate" ]] &&
       # Only display if the state __changed__!
       [[ "$laststate" != "$curstate" ]]
    then
       # jump to one of display_* functions, depending on state 
       "display_$curstate"
    fi
    laststate=$curstate
    #
    sleep 5
done
  • Related