0

I have a (for me atleast) quite complicated question.

See below:

#! /bin/bash

notify=false

a=0
while ((a <= 50))
do
    echo $a
    a=$(echo "$a+1" | bc)
    sleep 3s
done

When I run the script, the while loop goes and does it's thing. When it's done, the script exits.

The Question:

If I set the variable notify inside the script to true, something needs to happen. And that is that it sets a variable (e.g. notify_now) to true when $a reaches 25. When notify_now is set to true, it echo's a notification that doesn't interrupt the while loop. See below:

...
24
25
The variable $a has reached 25
26
...

But when I set notify to false, it doesn't give any notifications. See below:

...
24
25
26
...

Doing the following isn't an option in my actual situation:

#! /bin/bash

notify=false

a=0
while ((a <= 50))
do
    echo $a
    if ((a = 25)) && [[ $notify = true ]]
    then
    echo "The variable \$a has reached 25"
    fi
    a=$(echo "$a+1" | bc)
    sleep 3s
done

In summary:

I need a piece of code that is able to be run outside of the loop when a variable is set to true. The code needs to be run in the background so that the while loop can run in the foreground. When that piece of code in the background has noticed that the variable $a in the foreground has reached 25, it echo's a sentence in the terminal.

How far I got:

  • The piece of code is probably going to be a function that will be called
  • The function will be run in the background but echo's in the foreground (using &, but I'm really bad at that so that's why I'm asking this)
  • The code will be in a loop that will run until $a has reached 25 (so it will be checking $a as fast as a while loop goes until it is 25)

But I can't seem to be able to get any actual code to work.

Thanks!

2
  • 1
    Why do you need it?
    – choroba
    Mar 5 at 14:32
  • 1
    instead of a=$(echo "$a+1" | bc) you can add it to the while loop, while ((a++<50)) and it should be if ((a == 25)), and if you have no intention to expand, e.g., a variable you can use echo 'variable $a is 25'
    – bac0n
    Mar 5 at 14:39
1

This is where the bash DEBUG trap is handy. Ref https://www.gnu.org/software/bash/manual/bash.html#index-trap

If notify.sh contains

#!/bin/bash

has_been_notified=false
notify() {
    $has_been_notified && return
    if [[ -v a ]] && ((a == 25)); then
        echo "This is the notification: value is $a"
        has_been_notified=true
    fi
}

while getopts :n opt; do
    [[ $opt == n ]] && trap notify DEBUG
done
shift $((OPTIND - 1))

a=23
while ((a <= 27)); do
    echo $((a++))
done

Note that I'm using command line options instead of a $notify variable. Use whatever is convenient for you.

Running it:

$ bash notify.sh   # no notify
23
24
25
26
27

$ bash notify.sh -n    # with notify
23
24
This is the notification: value is 25
25
26
27

DEBUG traps are called before, basically, every command (see the manual for details). That's why I added the "has_been_notified" flag, so notifications only appear once.

This is a pretty heavy hammer for this job, but bash does not provide any finer traps, for example a trap for when a variable gets a new value.


Without the command line option:

#!/bin/bash
notify_flag=false

has_been_notified=false
notify() {
    $has_been_notified && return
    if [[ -v a ]] && ((a == 25)); then
        echo "This is the notification: value is $a"
        has_been_notified=true
    fi
}

[[ $notify_flag == true ]] && trap notify DEBUG

a=23
while ((a <= 27)); do
    echo $((a++))
done
6
  • Thank you very much. The code you gave is indeed quite complicated. I can barely understand it. How do I transform the code from command line option to a $notify variable?
    – Cas
    Mar 5 at 20:50
  • How do I transform the code to use the variable instead of the command line option?
    – Cas
    Mar 6 at 12:44
  • what does if [[ -v a ]] do? I can't find the meaning of -v anywhere. And I know that when you use ((...)), you don't have to put $ before a variable. But why isn't there a $ before a in the if-statement with -v?
    – Cas
    Mar 7 at 10:58
  • Sorry for spamming the comments. I got it to work in my script so that's great! The only thing is that in the real situation, it isn't a == 25 but [[apirequest]] = false. This makes it that everytime the script executes a command, the notify function makes an apirequest (due to DEBUG). Due to this, the script becomes very slow. Is there a way to check every 5 seconds instead of every execution? My script (2600 lines) executes so many commands in a short time, that it makes so many api requests that the script becomes unusable.
    – Cas
    Mar 7 at 11:29
  • For -v see help test from a bash prompt. -v takes a variable name Mar 7 at 12:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.