Loop ignora a mudança de variável de um subshell em segundo plano

5

Eu escrevi um script que contém um loop until . Esse loop deve ser executado até que uma variável booleana seja definida como true fora do loop. Infelizmente, o loop ignora que a variável foi definida como true e continua em execução. Aqui estão algumas linhas que geram esse problema:

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"

A saída gerada é:

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

Como posso fazer o loop sair quando o boolean estiver definido como true ?

    
por tigger92 25.08.2015 / 14:25

3 respostas

8

O caractere & faz um processo em segundo plano. Um processo em segundo plano é executado de forma assíncrona em um subshell. As variáveis podem ser passadas de um shell pai para um sub shell, e não o contrário. No entanto, você pode fazer uma solução alternativa se realmente precisar do valor definido no shell filho:

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)"

Isso cria um arquivo temporário cujo conteúdo é o valor booleano. No loop until , esse arquivo é verificado até conter true.

Aviso:

Eu recomendo fazer o seguinte no seu script (se possível):

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

wait espera que o processo em segundo plano termine.

    
por 25.08.2015 / 14:48
13

É possível usar sinais para se comunicar entre as camadas de primeiro e segundo plano:

#!/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"

saída

before: false
waiting...
waiting...
waiting...
waiting...
waiting...
finished background process
after: true
    
por 25.08.2015 / 15:05
4

Você supõe erroneamente que o boolean que você definiu como verdadeiro na segunda linha é o mesmo booleano que você testou na instrução until . Esse não é o caso, você inicia um novo processo, com um novo shell em segundo plano e boolean (aquele que você testa), nunca é atribuído.

    
por 25.08.2015 / 14:31