5

I wrote a script that contains an until loop. This loop should run till a boolean variable is set to true from outside the loop. Unfortunately the loop ignores that the variable has been set to true and keeps running. Here are a few lines which generate this problem:

boolean=false
{ sleep 5 && boolean=true && echo "boolean is true now" ; } &
{ until [ "$boolean" = true ] ; do sleep 1 && echo $boolean ; done ; } &&
echo "boolean is true now: $boolean"

The output this generates is:

false
false
false
false
boolean is true now
false
false
false
...

How can I make the loop exit when the boolean is set to true?

8

The & character makes a background process. A background process is executed asynchronously in a subshell. Variables can be passed from a parent shell to sub shell, not the other way around. However, you can do a workaround if you are really in need of the value set in the child shell:

boolean=$(mktemp) && echo "false" >$boolean
{ sleep 5 && echo true >$boolean && echo "boolean is true now" ; } &
{ until [ "$(cat $boolean)" = "true" ] ; do sleep 1 && cat $boolean ; done ; } &&
echo "boolean is true now: $(cat $boolean)"

That makes a temporary file whose content is the boolean value. In the until loop that file is checked until it contains true.

Notice:

I recommend to do the following in your script (if possible):

{ sleep 5 && echo "background process done" ; } &
wait
echo "continue in foregound."

wait waits for the background process to finish.

  • Thanks. This works fine. I would use wait but the background process in my script is always running. – tigger92 Aug 25 '15 at 13:00
  • What's the point of running something asynchronously, then waiting for it to finish? Just run it normally. – immibis Aug 26 '15 at 3:51
  • @immibis I think that between the job and the wait the asker has some code. – chaos Aug 26 '15 at 5:26
13

It's possible to use signals to communicate between the foreground and background shells:

#!/bin/bash

# global variable for foreground shell
boolean=false

# register a signal handler for SIGUSR1
trap handler USR1

# the handler sets the global variable
handler() { boolean=true; }

echo "before: $boolean"

# Here, "$$" is the pid of the foreground shell
{ sleep 5; kill -USR1 $$; echo "finished background process"; } &

# busy waiting
until $boolean; do 
    echo "waiting..."
    sleep 1
done

echo "after: $boolean"

output

before: false
waiting...
waiting...
waiting...
waiting...
waiting...
finished background process
after: true
  • 1
    +1 Signals are the right way to pass asynchronous notifications between processes. – alexis Aug 26 '15 at 9:22
4

You mistakenly assume that the boolean you set to true in the second line is the same boolean that you test for in the until statement. That is not the case, you start new process, with a new shell in the background and boolean (the one you test for), never gets assigned.

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.